MXS-1249: Server version stored as uint64_t value
That allows the version to be updated and read atomically. If major/minor/patch are stored as separate variables, you can get an inconsistent set. Now it may be out of date by the time it is used, but it will never be internally inconsistent.
This commit is contained in:
parent
4e73aecdef
commit
997416ab82
@ -73,6 +73,22 @@ typedef struct server_version
|
||||
uint32_t patch;
|
||||
} SERVER_VERSION;
|
||||
|
||||
static inline void server_decode_version(uint64_t version, SERVER_VERSION* server_version)
|
||||
{
|
||||
uint32_t major = version / 10000;
|
||||
uint32_t minor = (version - major * 10000) / 100;
|
||||
uint32_t patch = version - major * 10000 - minor * 100;
|
||||
|
||||
server_version->major = major;
|
||||
server_version->minor = minor;
|
||||
server_version->patch = patch;
|
||||
}
|
||||
|
||||
static uint64_t server_encode_version(const SERVER_VERSION* server_version)
|
||||
{
|
||||
return server_version->major * 10000 + server_version->minor * 100 + server_version->patch;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SERVER structure defines a backend server. Each server has a name
|
||||
* or IP address for the server, a port that the server listens on and
|
||||
@ -101,7 +117,7 @@ typedef struct server
|
||||
struct server *next; /**< Next server */
|
||||
struct server *nextdb; /**< Next server in list attached to a service */
|
||||
char version_string[MAX_SERVER_VERSION_LEN]; /**< Server version string, i.e. MySQL server version */
|
||||
SERVER_VERSION version; /**< Server version information */
|
||||
uint64_t version; /**< Server version */
|
||||
long node_id; /**< Node id, server_id for M/S or local_index for Galera */
|
||||
int rlag; /**< Replication Lag for Master / Slave replication */
|
||||
unsigned long node_ts; /**< Last timestamp set from M/S monitor module */
|
||||
@ -321,8 +337,9 @@ extern DCB *server_get_persistent(SERVER *server, const char *user, const char
|
||||
extern void server_update_address(SERVER *server, const char *address);
|
||||
extern void server_update_port(SERVER *server, unsigned short port);
|
||||
extern unsigned int server_map_status(const char *str);
|
||||
extern void server_set_version_string(SERVER* server, const char* string);
|
||||
extern void server_set_version(SERVER* server, const char* string, uint32_t major, uint32_t minor, uint32_t patch);
|
||||
extern void server_set_version_string(SERVER* server, const char* version_string);
|
||||
extern void server_set_version(SERVER* server, const char* version_string, uint64_t version);
|
||||
extern uint64_t server_get_version(const SERVER* server);
|
||||
extern void server_set_status(SERVER *server, int bit);
|
||||
extern void server_clear_status(SERVER *server, int bit);
|
||||
|
||||
|
@ -378,6 +378,6 @@ typedef enum service_version_which_t
|
||||
*/
|
||||
void service_get_version(const SERVICE *service,
|
||||
service_version_which_t which,
|
||||
SERVER_VERSION* version);
|
||||
uint64_t* version);
|
||||
|
||||
MXS_END_DECLS
|
||||
|
@ -288,16 +288,12 @@ mxs_mysql_name_kind_t mxs_mysql_name_to_pcre(char *pcre,
|
||||
|
||||
void mxs_mysql_set_server_version(MYSQL* mysql, SERVER* server)
|
||||
{
|
||||
const char* s = mysql_get_server_info(mysql);
|
||||
const char* version_string = mysql_get_server_info(mysql);
|
||||
|
||||
if (s)
|
||||
if (version_string)
|
||||
{
|
||||
unsigned long v = mysql_get_server_version(mysql);
|
||||
unsigned long version = mysql_get_server_version(mysql);
|
||||
|
||||
unsigned long major = v / 10000;
|
||||
unsigned long minor = (v - major * 10000) / 100;
|
||||
unsigned long patch = v - major * 10000 - minor * 100;
|
||||
|
||||
server_set_version(server, s, major, minor, patch);
|
||||
server_set_version(server, version_string, version);
|
||||
}
|
||||
}
|
||||
|
@ -1076,17 +1076,17 @@ server_map_status(const char *str)
|
||||
/**
|
||||
* Set the version string of the server.
|
||||
*
|
||||
* @param server Server to update
|
||||
* @param version Version string
|
||||
* @param server Server to update
|
||||
* @param version_string Version string
|
||||
*/
|
||||
void server_set_version_string(SERVER* server, const char* version)
|
||||
void server_set_version_string(SERVER* server, const char* version_string)
|
||||
{
|
||||
// There is a race here. The string may be accessed, while we are
|
||||
// updating it. Thus we take some precautions to ensure that the
|
||||
// string cannot be completely garbled at any point.
|
||||
|
||||
size_t old_len = strlen(server->version_string);
|
||||
size_t new_len = strlen(version);
|
||||
size_t new_len = strlen(version_string);
|
||||
|
||||
if (new_len >= MAX_SERVER_VERSION_LEN)
|
||||
{
|
||||
@ -1100,7 +1100,7 @@ void server_set_version_string(SERVER* server, const char* version)
|
||||
memset(server->version_string + new_len, 0, old_len - new_len);
|
||||
}
|
||||
|
||||
strncpy(server->version_string, version, new_len);
|
||||
strncpy(server->version_string, version_string, new_len);
|
||||
// No null-byte needs to be set. The array starts out as all zeros
|
||||
// and the above memset adds the necessary null, should the new string
|
||||
// be shorter than the old.
|
||||
@ -1109,19 +1109,21 @@ void server_set_version_string(SERVER* server, const char* version)
|
||||
/**
|
||||
* Set the version of the server.
|
||||
*
|
||||
* @param server Server to update
|
||||
* @param string Human readable version string.
|
||||
* @param major The major version.
|
||||
* @param minor The minor version.
|
||||
* @param patch The patch version.
|
||||
* @param server Server to update
|
||||
* @param version_string Human readable version string.
|
||||
* @param version Version encoded as MariaDB encodes the version, i.e.:
|
||||
* version = major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
void server_set_version(SERVER* server, const char* string, uint32_t major, uint32_t minor, uint32_t patch)
|
||||
void server_set_version(SERVER* server, const char* version_string, uint64_t version)
|
||||
{
|
||||
server_set_version_string(server, string);
|
||||
server_set_version_string(server, version_string);
|
||||
|
||||
server->version.major = major;
|
||||
server->version.minor = minor;
|
||||
server->version.patch = patch;
|
||||
atomic_store_uint64(&server->version, version);
|
||||
}
|
||||
|
||||
uint64_t server_get_version(const SERVER* server)
|
||||
{
|
||||
return atomic_load_uint64(&server->version);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2676,7 +2676,7 @@ json_t* service_relations_to_server(const SERVER* server, const char* host)
|
||||
|
||||
void service_get_version(const SERVICE *service,
|
||||
service_version_which_t which,
|
||||
SERVER_VERSION* version)
|
||||
uint64_t* version)
|
||||
{
|
||||
if (which == SERVICE_VERSION_ANY)
|
||||
{
|
||||
@ -2689,32 +2689,28 @@ void service_get_version(const SERVICE *service,
|
||||
|
||||
if (sref)
|
||||
{
|
||||
*version = sref->server->version;
|
||||
*version = server_get_version(sref->server);
|
||||
}
|
||||
else
|
||||
{
|
||||
version->major = version->minor = version->patch = 0;
|
||||
*version = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
SERVER_VERSION v;
|
||||
uint64_t v;
|
||||
|
||||
if (which == SERVICE_VERSION_MIN)
|
||||
{
|
||||
v.major = UINT32_MAX;
|
||||
v.minor = UINT32_MAX;
|
||||
v.patch = UINT32_MAX;
|
||||
v = UINT64_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss_dassert(which == SERVICE_VERSION_MAX);
|
||||
|
||||
v.major = 0;
|
||||
v.minor = 0;
|
||||
v.patch = 0;
|
||||
v = 0;
|
||||
}
|
||||
|
||||
SERVER_REF* sref = service->dbref;
|
||||
@ -2726,25 +2722,22 @@ void service_get_version(const SERVICE *service,
|
||||
++n;
|
||||
|
||||
SERVER* s = sref->server;
|
||||
uint64_t server_version = server_get_version(s);
|
||||
|
||||
if (which == SERVICE_VERSION_MIN)
|
||||
{
|
||||
if ((s->version.major < v.major) ||
|
||||
((s->version.major == v.major) && (s->version.minor < v.minor)) ||
|
||||
((s->version.major == v.major) && (s->version.minor == v.minor) &&
|
||||
(s->version.patch < v.patch)))
|
||||
if (server_version < v)
|
||||
{
|
||||
v = s->version;
|
||||
v = server_version;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((s->version.major > v.major) ||
|
||||
((s->version.major == v.major) && (s->version.minor > v.minor)) ||
|
||||
((s->version.major == v.major) && (s->version.minor == v.minor) &&
|
||||
(s->version.patch > v.patch)))
|
||||
ss_dassert(which == SERVICE_VERSION_MAX);
|
||||
|
||||
if (server_version > v)
|
||||
{
|
||||
v = s->version;
|
||||
v = server_version;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2754,7 +2747,7 @@ void service_get_version(const SERVICE *service,
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
v.major = v.minor = v.patch = 0;
|
||||
v = 0;
|
||||
}
|
||||
|
||||
*version = v;
|
||||
|
Loading…
x
Reference in New Issue
Block a user