Fixed weightby overflow being silently ignored in readwritesplit

If individual servers had a weightby parameter value greater than INT_MAX * 1000
the integer used for calculation would overflow and the server would end up
having a negative weight. This would cause all connections to pile up on this
server.

The same overflow was possible for the sum of all the weightby parameter values
even if no single parameter exceeded the limit.
This commit is contained in:
Markus Makela
2015-11-25 22:30:51 +02:00
parent b0458b3cc4
commit 8ae187622c

View File

@ -628,47 +628,68 @@ createInstance(SERVICE *service, char **options)
*/ */
if ((weightby = serviceGetWeightingParameter(service)) != NULL) if ((weightby = serviceGetWeightingParameter(service)) != NULL)
{ {
int n, total = 0; int total = 0;
BACKEND *backend;
for (n = 0; router->servers[n]; n++) for (int n = 0; router->servers[n]; n++)
{ {
backend = router->servers[n]; BACKEND *backend = router->servers[n];
total += atoi(serverGetParameter( char *param = serverGetParameter(backend->backend_server, weightby);
backend->backend_server, weightby)); if (param)
{
total += atoi(param);
}
} }
if (total == 0) if (total == 0)
{ {
MXS_WARNING("Weighting Parameter for service '%s' " MXS_WARNING("Weighting Parameter for service '%s' "
"will be ignored as no servers have values " "will be ignored as no servers have values "
"for the parameter '%s'.\n", "for the parameter '%s'.",
service->name, weightby); service->name, weightby);
} }
else if (total < 0)
{
MXS_ERROR("Sum of weighting parameter '%s' for service '%s' exceeds "
"maximum value of %d. Weighting will be ignored.",
weightby, service->name, INT_MAX);
}
else else
{ {
for (n = 0; router->servers[n]; n++) for (int n = 0; router->servers[n]; n++)
{ {
int perc; BACKEND *backend = router->servers[n];
int wght; char *param = serverGetParameter(backend->backend_server, weightby);
backend = router->servers[n]; if (param)
wght = atoi(serverGetParameter(backend->backend_server,
weightby));
perc = (wght*1000) / total;
if (perc == 0 && wght != 0)
{ {
perc = 1; int wght = atoi(param);
} int perc = (wght * 1000) / total;
backend->weight = perc;
if (perc == 0) if (perc == 0)
{ {
MXS_ERROR("Server '%s' has no value " if (wght != 0)
"for weighting parameter '%s', " {
"no queries will be routed to " perc = 1;
"this server.\n", }
router->servers[n]->backend_server->unique_name, MXS_ERROR("Weighting parameter '%s' with a value of %d for"
weightby); " server '%s' rounds down to zero with total weight"
" of %d for service '%s'. No queries will be "
"routed to this server.", weightby, wght,
backend->backend_server->unique_name, total,
service->name);
}
else if (perc < 0)
{
MXS_ERROR("Weighting parameter '%s' for server '%s' is too large, "
"maximum value is %d. No weighting will be used for this server.",
weightby, backend->backend_server->unique_name, INT_MAX / 1000);
perc = 1000;
}
backend->weight = perc;
}
else
{
MXS_WARNING("Server '%s' has no parameter '%s' used for weighting"
" for service '%s'.", backend->backend_server->unique_name,
weightby, service->name);
} }
} }
} }