MXS-2313: Use rank in readwritesplit
Readwritesplit now respects server ranks. When servers are selected for either routing or connection creation, the servers are partitioned by their rank into sets of servers. These sets of servers are never mixed so the end result is that only servers of the same rank are considered for candidacy. The master selection is slightly different: the server with the best rank that is capable of acting as a master is chosen. This means that a session can have a master with a lower rank and slaves with higher ranks than the master. In most cases this actually is the preferred behavior as the rank is used to prioritize usage but not outright prevent it.
This commit is contained in:
@ -202,35 +202,13 @@ BackendSelectFunction get_backend_select_function(select_criteria_t sc)
|
||||
return backend_cmp_current_load;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find the best slave candidate for routing reads.
|
||||
*
|
||||
* @param backends All backends
|
||||
* @param select Server selection function
|
||||
* @param masters_accepts_reads
|
||||
*
|
||||
* @return iterator to the best slave or backends.end() if none found
|
||||
*/
|
||||
PRWBackends::iterator find_best_backend(PRWBackends& backends,
|
||||
BackendSelectFunction select,
|
||||
bool masters_accepts_reads)
|
||||
// Calculates server priority
|
||||
int get_backend_priority(RWBackend* backend, bool masters_accepts_reads)
|
||||
{
|
||||
// Group backends by priority. The set of highest priority backends will then compete.
|
||||
int best_priority {INT_MAX}; // low numbers are high priority
|
||||
thread_local std::array<PRWBackends, 3> priority_map;
|
||||
|
||||
for (auto& a : priority_map)
|
||||
{
|
||||
a.clear();
|
||||
}
|
||||
|
||||
for (auto& psBackend : backends)
|
||||
{
|
||||
auto& backend = *psBackend;
|
||||
bool is_busy = backend.in_use() && backend.has_session_commands();
|
||||
bool acts_slave = backend.is_slave() || (backend.is_master() && masters_accepts_reads);
|
||||
|
||||
int priority;
|
||||
bool is_busy = backend->in_use() && backend->has_session_commands();
|
||||
bool acts_slave = backend->is_slave() || (backend->is_master() && masters_accepts_reads);
|
||||
|
||||
if (acts_slave)
|
||||
{
|
||||
if (!is_busy)
|
||||
@ -247,21 +225,68 @@ PRWBackends::iterator find_best_backend(PRWBackends& backends,
|
||||
priority = 1; // idle masters with masters_accept_reads==false
|
||||
}
|
||||
|
||||
priority_map[priority].push_back(psBackend);
|
||||
best_priority = std::min(best_priority, priority);
|
||||
}
|
||||
return priority;
|
||||
}
|
||||
|
||||
auto best = select(priority_map[best_priority]);
|
||||
auto rval = backends.end();
|
||||
/**
|
||||
* @brief Find the best slave candidate for routing reads.
|
||||
*
|
||||
* @param backends All backends
|
||||
* @param select Server selection function
|
||||
* @param masters_accepts_reads
|
||||
*
|
||||
* @return iterator to the best slave or backends.end() if none found
|
||||
*/
|
||||
PRWBackends::iterator find_best_backend(PRWBackends& backends,
|
||||
BackendSelectFunction select,
|
||||
bool masters_accepts_reads)
|
||||
{
|
||||
// Group backends by priority and rank (lower is better). The set of best backends will then compete.
|
||||
int best_priority {INT_MAX};
|
||||
int best_rank {std::numeric_limits<int>::max()};
|
||||
thread_local PRWBackends candidates;
|
||||
candidates.clear();
|
||||
|
||||
if (best != priority_map[best_priority].end())
|
||||
for (auto& psBackend : backends)
|
||||
{
|
||||
rval = std::find(backends.begin(), backends.end(), *best);
|
||||
int priority = get_backend_priority(psBackend, masters_accepts_reads);
|
||||
int rank = psBackend->server()->rank();
|
||||
|
||||
if (rank < best_rank || (rank == best_rank && priority < best_priority))
|
||||
{
|
||||
candidates.clear();
|
||||
best_rank = rank;
|
||||
best_priority = priority;
|
||||
}
|
||||
|
||||
if (rank == best_rank && priority == best_priority)
|
||||
{
|
||||
candidates.push_back(psBackend);
|
||||
}
|
||||
}
|
||||
|
||||
auto best = select(candidates);
|
||||
auto rval = std::find(backends.begin(), backends.end(), *best);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
void add_backend_with_rank(RWBackend* backend, PRWBackends* candidates, int* best_rank)
|
||||
{
|
||||
int rank = backend->server()->rank();
|
||||
|
||||
if (rank < *best_rank)
|
||||
{
|
||||
*best_rank = rank;
|
||||
candidates->clear();
|
||||
}
|
||||
|
||||
if (rank == *best_rank)
|
||||
{
|
||||
candidates->push_back(backend);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Log server connections
|
||||
*
|
||||
@ -339,17 +364,20 @@ RWBackend* get_root_master(const PRWBackends& backends, RWBackend* current_maste
|
||||
return current_master;
|
||||
}
|
||||
|
||||
thread_local PRWBackends sort_buffer;
|
||||
sort_buffer.clear();
|
||||
thread_local PRWBackends candidates;
|
||||
candidates.clear();
|
||||
int best_rank {std::numeric_limits<int>::max()};
|
||||
|
||||
std::copy_if(backends.begin(), backends.end(), std::back_inserter(sort_buffer),
|
||||
[](RWBackend* backend) {
|
||||
return backend->can_connect() && backend->is_master();
|
||||
});
|
||||
for (const auto& backend : backends)
|
||||
{
|
||||
if (backend->can_connect() && backend->is_master())
|
||||
{
|
||||
add_backend_with_rank(backend, &candidates, &best_rank);
|
||||
}
|
||||
}
|
||||
|
||||
auto it = func(sort_buffer);
|
||||
|
||||
return it != sort_buffer.end() ? *it : nullptr;
|
||||
auto it = func(candidates);
|
||||
return it != candidates.end() ? *it : nullptr;
|
||||
}
|
||||
|
||||
std::pair<int, int> get_slave_counts(PRWBackends& backends, RWBackend* master)
|
||||
@ -421,6 +449,7 @@ bool RWSplitSession::open_connections()
|
||||
|
||||
int n_slaves = get_slave_counts(m_raw_backends, master).second;
|
||||
int max_nslaves = m_router->max_slave_count();
|
||||
int best_rank {std::numeric_limits<int>::max()};
|
||||
PRWBackends candidates;
|
||||
mxb_assert(n_slaves <= max_nslaves || max_nslaves == 0);
|
||||
|
||||
@ -428,7 +457,7 @@ bool RWSplitSession::open_connections()
|
||||
{
|
||||
if (!pBackend->in_use() && pBackend->can_connect() && valid_for_slave(pBackend, master))
|
||||
{
|
||||
candidates.push_back(pBackend);
|
||||
add_backend_with_rank(pBackend, &candidates, &best_rank);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user