MXS-1845 Save cycle members

The saved data may be useful later on. Also includes some cleanup.
This commit is contained in:
Esa Korhonen
2018-05-31 14:45:41 +03:00
parent 19a0c94661
commit 9a0445cd4e
2 changed files with 38 additions and 23 deletions

View File

@ -231,18 +231,18 @@ MXS_MONITORED_SERVER* MariaDBMonitor::getSlaveOfNodeId(long node_id, slave_down_
*
* @param node Target server/node
* @param stack The stack used by the algorithm, contains nodes which have not yet been assigned a cycle
* @param index Visitation index of next node
* @param cycle Index of next found cycle
* @param next_ind Visitation index of next node
* @param next_cycle Index of next found cycle
*/
void MariaDBMonitor::tarjan_ssc_visit_node(MariaDBServer *node, ServerArray* stack,
int *index, int *cycle)
void MariaDBMonitor::tarjan_scc_visit_node(MariaDBServer *node, ServerArray* stack,
int *next_ind, int *next_cycle)
{
/** Assign an index to this node */
NodeData& node_info = node->m_node;
auto ind = *index;
auto ind = *next_ind;
node_info.index = ind;
node_info.lowest_index = ind;
*index = ind + 1;
*next_ind = ind + 1;
if (node_info.parents.empty())
{
@ -261,7 +261,7 @@ void MariaDBMonitor::tarjan_ssc_visit_node(MariaDBServer *node, ServerArray* sta
if (parent_node.index == NodeData::INDEX_NOT_VISITED)
{
/** Node has not been visited, so recurse. */
tarjan_ssc_visit_node((*iter), stack, index, cycle);
tarjan_scc_visit_node((*iter), stack, next_ind, next_cycle);
node_info.lowest_index = MXS_MIN(node_info.lowest_index, parent_node.lowest_index);
}
else if (parent_node.in_stack)
@ -280,10 +280,12 @@ void MariaDBMonitor::tarjan_ssc_visit_node(MariaDBServer *node, ServerArray* sta
if (node_info.index == node_info.lowest_index)
{
int cycle_size = 0; // Keep track of cycle size since we don't mark one-node cycles.
auto cycle_ind = *next_cycle;
while (true)
{
ss_dassert(!stack->empty());
NodeData& cycle_node = stack->back()->m_node;
MariaDBServer* cycle_server = stack->back();
NodeData& cycle_node = cycle_server->m_node;
stack->pop_back();
cycle_node.in_stack = false;
cycle_size++;
@ -291,15 +293,19 @@ void MariaDBMonitor::tarjan_ssc_visit_node(MariaDBServer *node, ServerArray* sta
{
if (cycle_size > 1)
{
cycle_node.cycle = *cycle;
cycle_node.cycle = cycle_ind;
ServerArray& members = m_cycles[cycle_ind]; // Creates array if didn't exist
members.push_back(cycle_server);
// All cycle elements popped. Next cycle...
*cycle = *cycle + 1;
*next_cycle = cycle_ind + 1;
}
break;
}
else
{
cycle_node.cycle = *cycle; // Has more nodes, mark cycle.
cycle_node.cycle = cycle_ind; // Has more nodes, mark cycle.
ServerArray& members = m_cycles[cycle_ind];
members.push_back(cycle_server);
}
}
}
@ -308,18 +314,23 @@ void MariaDBMonitor::tarjan_ssc_visit_node(MariaDBServer *node, ServerArray* sta
void MariaDBMonitor::build_replication_graph()
{
// First, reset all node data.
for (auto iter = m_servers.begin(); iter != m_servers.end(); iter++)
{
(*iter)->m_node.reset();
}
/* Here, all slave connections are added to the graph, even if the IO thread cannot connect. Strictly
* speaking, building the parents-array is not required as the data already exists. This construction
* is more for convenience and faster access. */
* is more for convenience and faster access later on. */
for (auto iter = m_servers.begin(); iter != m_servers.end(); iter++)
{
/* All servers are accepted in this loop, even if the server is [Down] or [Maintenance]. For these
* servers, we just use the latest available information. Not adding such servers could suddenly
* change the topology quite a bit and all it would take is a momentarily network failure. */
MariaDBServer* server = *iter;
server->m_node.reset();
MariaDBServer* slave = *iter;
for (auto iter_ss = server->m_slave_status.begin(); iter_ss != server->m_slave_status.end();
for (auto iter_ss = slave->m_slave_status.begin(); iter_ss != slave->m_slave_status.end();
iter_ss++)
{
SlaveStatus& slave_conn = *iter_ss;
@ -332,16 +343,16 @@ void MariaDBMonitor::build_replication_graph()
if (slave_conn.slave_io_running != SlaveStatus::SLAVE_IO_NO && master_id > 0)
{
// Valid slave connection, find the MariaDBServer with this id.
auto found = get_server(master_id);
if (found != NULL)
auto master = get_server(master_id);
if (master != NULL)
{
server->m_node.parents.push_back(found);
found->m_node.children.push_back(server);
slave->m_node.parents.push_back(master);
master->m_node.children.push_back(slave);
}
else
{
// This is an external master connection. Save just the master id for now.
server->m_node.external_masters.push_back(master_id);
slave->m_node.external_masters.push_back(master_id);
}
}
}
@ -368,8 +379,9 @@ void MariaDBMonitor::build_replication_graph()
void MariaDBMonitor::find_graph_cycles()
{
build_replication_graph();
ServerArray stack;
m_cycles.clear();
// The next items need to be passed around in the recursive calls to keep track of algorithm state.
ServerArray stack;
int index = 1; // Node visit index.
int cycle = 1; // If cycles are found, the nodes in the cycle are given an identical cycle index.
@ -378,7 +390,7 @@ void MariaDBMonitor::find_graph_cycles()
/** Index is 0, this node has not yet been visited. */
if ((*iter)->m_node.index == NodeData::INDEX_NOT_VISITED)
{
tarjan_ssc_visit_node(*iter, &stack, &index, &cycle);
tarjan_scc_visit_node(*iter, &stack, &index, &cycle);
}
}

View File

@ -32,6 +32,8 @@ class MariaDBMonitor;
typedef std::tr1::unordered_map<MXS_MONITORED_SERVER*, MariaDBServer*> ServerInfoMap;
// Map of server id:s to MariaDBServer. Useful when constructing the replication graph.
typedef std::tr1::unordered_map<int64_t, MariaDBServer*> IdToServerMap;
// Map of cycle number to cycle members
typedef std::tr1::unordered_map<int, ServerArray> CycleMap;
// MariaDB Monitor instance data
class MariaDBMonitor : public maxscale::MonitorInstance
@ -102,6 +104,7 @@ private:
unsigned long m_id; /**< Monitor ID */
ServerArray m_servers; /**< Servers of the monitor */
ServerInfoMap m_server_info; /**< Map from server base struct to MariaDBServer */
CycleMap m_cycles; /**< Map from cycle number to cycle member servers */
// Values updated by monitor
MariaDBServer* m_master; /**< Master server for Master/Slave replication */
@ -176,7 +179,7 @@ private:
MXS_MONITORED_SERVER* getServerByNodeId(long);
MXS_MONITORED_SERVER* getSlaveOfNodeId(long, slave_down_setting_t);
void build_replication_graph();
void tarjan_ssc_visit_node(MariaDBServer *node, ServerArray* stack, int *index,
void tarjan_scc_visit_node(MariaDBServer *node, ServerArray* stack, int *index,
int *cycle);
void assign_cycle_roles(int cycle);