237 lines
6.3 KiB
C++
237 lines
6.3 KiB
C++
/*
|
|
* Copyright (c) 2018 MariaDB Corporation Ab
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
*
|
|
* Change Date: 2023-11-12
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2 or later of the General
|
|
* Public License.
|
|
*/
|
|
|
|
#include "clustrix.hh"
|
|
#include <maxbase/assert.h>
|
|
|
|
using maxscale::Monitor;
|
|
using maxscale::MonitorServer;
|
|
|
|
namespace
|
|
{
|
|
|
|
const char CN_DYNAMIC[] = "dynamic";
|
|
const char CN_NORMAL[] = "normal";
|
|
const char CN_QUORUM[] = "quorum";
|
|
const char CN_STATIC[] = "static";
|
|
const char CN_UNKNOWN[] = "unknown";
|
|
}
|
|
|
|
std::string Clustrix::to_string(Clustrix::Status status)
|
|
{
|
|
switch (status)
|
|
{
|
|
case Status::QUORUM:
|
|
return CN_QUORUM;
|
|
|
|
case Status::STATIC:
|
|
return CN_STATIC;
|
|
|
|
case Status::DYNAMIC:
|
|
return CN_DYNAMIC;
|
|
|
|
case Status::UNKNOWN:
|
|
return CN_UNKNOWN;
|
|
}
|
|
|
|
mxb_assert(!true);
|
|
return CN_UNKNOWN;
|
|
}
|
|
|
|
Clustrix::Status Clustrix::status_from_string(const std::string& status)
|
|
{
|
|
if (status == CN_QUORUM)
|
|
{
|
|
return Status::QUORUM;
|
|
}
|
|
else if (status == CN_STATIC)
|
|
{
|
|
return Status::STATIC;
|
|
}
|
|
else if (status == CN_DYNAMIC)
|
|
{
|
|
return Status::DYNAMIC;
|
|
}
|
|
else
|
|
{
|
|
MXB_WARNING("'%s' is an unknown status for a Clustrix node.", status.c_str());
|
|
return Status::UNKNOWN;
|
|
}
|
|
}
|
|
|
|
std::string Clustrix::to_string(Clustrix::SubState substate)
|
|
{
|
|
switch (substate)
|
|
{
|
|
case SubState::NORMAL:
|
|
return CN_NORMAL;
|
|
|
|
case SubState::UNKNOWN:
|
|
return CN_UNKNOWN;
|
|
}
|
|
|
|
mxb_assert(!true);
|
|
return CN_UNKNOWN;
|
|
}
|
|
|
|
Clustrix::SubState Clustrix::substate_from_string(const std::string& substate)
|
|
{
|
|
if (substate == CN_NORMAL)
|
|
{
|
|
return SubState::NORMAL;
|
|
}
|
|
else
|
|
{
|
|
MXB_WARNING("'%s' is an unknown sub-state for a Clustrix node.", substate.c_str());
|
|
return SubState::UNKNOWN;
|
|
}
|
|
}
|
|
|
|
bool Clustrix::is_part_of_the_quorum(const char* zName, MYSQL* pCon)
|
|
{
|
|
bool rv = false;
|
|
|
|
const char ZQUERY[] = "SELECT status FROM system.membership WHERE nid = gtmnid()";
|
|
|
|
if (mysql_query(pCon, ZQUERY) == 0)
|
|
{
|
|
MYSQL_RES* pResult = mysql_store_result(pCon);
|
|
|
|
if (pResult)
|
|
{
|
|
mxb_assert(mysql_field_count(pCon) == 1);
|
|
|
|
MYSQL_ROW row = mysql_fetch_row(pResult);
|
|
if (row && row[0])
|
|
{
|
|
Clustrix::Status status = Clustrix::status_from_string(row[0]);
|
|
|
|
switch (status)
|
|
{
|
|
case Clustrix::Status::QUORUM:
|
|
rv = true;
|
|
break;
|
|
|
|
case Clustrix::Status::STATIC:
|
|
MXS_NOTICE("%s: Node %s is not part of the quorum (static), switching to "
|
|
"other node for monitoring.",
|
|
zName, mysql_get_host_info(pCon));
|
|
break;
|
|
|
|
case Clustrix::Status::DYNAMIC:
|
|
MXS_NOTICE("%s: Node %s is not part of the quorum (dynamic), switching to "
|
|
"other node for monitoring.",
|
|
zName, mysql_get_host_info(pCon));
|
|
break;
|
|
|
|
case Clustrix::Status::UNKNOWN:
|
|
MXS_WARNING("%s: Do not know how to interpret '%s'. Assuming node %s "
|
|
"is not part of the quorum.",
|
|
zName, row[0], mysql_get_host_info(pCon));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXS_WARNING("%s: No status returned for '%s' on %s.",
|
|
zName, ZQUERY, mysql_get_host_info(pCon));
|
|
}
|
|
|
|
mysql_free_result(pResult);
|
|
}
|
|
else
|
|
{
|
|
MXS_WARNING("%s: No result returned for '%s' on %s.",
|
|
zName, ZQUERY, mysql_get_host_info(pCon));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXS_ERROR("%s: Could not execute '%s' on %s: %s",
|
|
zName, ZQUERY, mysql_get_host_info(pCon), mysql_error(pCon));
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
bool Clustrix::is_being_softfailed(const char* zName, MYSQL* pCon)
|
|
{
|
|
bool rv = false;
|
|
|
|
const char ZQUERY[] = "SELECT nodeid FROM system.softfailed_nodes WHERE nodeid = gtmnid()";
|
|
|
|
if (mysql_query(pCon, ZQUERY) == 0)
|
|
{
|
|
MYSQL_RES* pResult = mysql_store_result(pCon);
|
|
|
|
if (pResult)
|
|
{
|
|
mxb_assert(mysql_field_count(pCon) == 1);
|
|
|
|
MYSQL_ROW row = mysql_fetch_row(pResult);
|
|
if (row)
|
|
{
|
|
// If a row is found, it is because the node is being softfailed.
|
|
rv = true;
|
|
}
|
|
|
|
mysql_free_result(pResult);
|
|
}
|
|
else
|
|
{
|
|
MXS_WARNING("%s: No result returned for '%s' on %s.",
|
|
zName, ZQUERY, mysql_get_host_info(pCon));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXS_ERROR("%s: Could not execute '%s' on %s: %s",
|
|
zName, ZQUERY, mysql_get_host_info(pCon), mysql_error(pCon));
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
bool Clustrix::ping_or_connect_to_hub(const char* zName,
|
|
const MonitorServer::ConnectionSettings& settings,
|
|
Softfailed softfailed,
|
|
SERVER& server,
|
|
MYSQL** ppCon)
|
|
{
|
|
bool connected = false;
|
|
MonitorServer::ConnectResult rv = Monitor::ping_or_connect_to_db(settings, server, ppCon);
|
|
|
|
if (Monitor::connection_is_ok(rv))
|
|
{
|
|
if (Clustrix::is_part_of_the_quorum(zName, *ppCon))
|
|
{
|
|
if ((softfailed == Softfailed::REJECT) && Clustrix::is_being_softfailed(zName, *ppCon))
|
|
{
|
|
MXS_NOTICE("%s: The Clustrix node %s used as hub is part of the quorum, "
|
|
"but it is being softfailed. Switching to another node.",
|
|
zName, server.address);
|
|
}
|
|
else
|
|
{
|
|
connected = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXS_ERROR("%s: Could either not ping or create connection to %s:%d: %s",
|
|
zName, server.address, server.port, mysql_error(*ppCon));
|
|
}
|
|
|
|
return connected;
|
|
}
|