Merge branch '2.3' into develop

This commit is contained in:
Esa Korhonen 2019-04-30 12:06:06 +03:00
commit 643514bbe4
11 changed files with 212 additions and 92 deletions

View File

@ -943,6 +943,9 @@ add_test_executable(mxs2313_rank.cpp mxs2313_rank mxs2313_rank LABELS readwrites
# MXS-2417: Ignore persisted configs with load_persisted_configs=false
add_test_executable(mxs2417_ignore_persisted_cnf.cpp mxs2417_ignore_persisted_cnf mxs2417_ignore_persisted_cnf LABELS REPL_BACKEND)
# MXS-2450: Crash on COM_CHANGE_USER with disable_sescmd_history=true
add_test_executable(mxs2450_change_user_crash.cpp mxs2450_change_user_crash mxs2450_change_user_crash LABELS REPL_BACKEND)
# MXS-1662: PAM admin authentication
add_test_executable(mxs1662_pam_admin.cpp mxs1662_pam_admin mxs1662_pam_admin LABELS REPL_BACKEND)

View File

@ -0,0 +1,49 @@
[maxscale]
threads=###threads###
log_info=1
[server1]
type=server
address=###node_server_IP_1###
port=###node_server_port_1###
protocol=MySQLBackend
[server2]
type=server
address=###node_server_IP_2###
port=###node_server_port_2###
protocol=MySQLBackend
[server3]
type=server
address=###node_server_IP_3###
port=###node_server_port_3###
protocol=MySQLBackend
[server4]
type=server
address=###node_server_IP_4###
port=###node_server_port_4###
protocol=MySQLBackend
[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2,server3,server4
user=maxskysql
password=skysql
monitor_interval=1000
[RW Split Router]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
user=maxskysql
password=skysql
disable_sescmd_history=true
[RW Split Listener]
type=listener
service=RW Split Router
protocol=MySQLClient
port=4006

View File

@ -4,17 +4,16 @@
#include <string>
#include "envv.h"
Maxscales::Maxscales(const char *pref, const char *test_cwd, bool verbose, bool use_valgrind,
Maxscales::Maxscales(const char *pref, const char *test_cwd, bool verbose,
std::string network_config)
{
strcpy(prefix, pref);
this->verbose = verbose;
this->use_valgrind = use_valgrind;
valgring_log_num = 0;
strcpy(test_dir, test_cwd);
this->network_config = network_config;
read_env();
if (use_valgrind)
if (this->use_valgrind)
{
for (int i = 0; i < N; i++)
{
@ -61,6 +60,13 @@ int Maxscales::read_env()
}
}
use_valgrind = readenv_bool("use_valgrind", false);
use_callgrind = readenv_bool("use_callgrind", false);
if (use_callgrind)
{
use_valgrind = true;
}
return 0;
}
@ -211,10 +217,23 @@ int Maxscales::start_maxscale(int m)
int res;
if (use_valgrind)
{
res = ssh_node_f(m, false,
"sudo --user=maxscale valgrind --leak-check=full --show-leak-kinds=all "
"--log-file=/%s/valgrind%02d.log --trace-children=yes "
"--track-origins=yes /usr/bin/maxscale", maxscale_log_dir[m], valgring_log_num);
if (use_callgrind)
{
res = ssh_node_f(m, false,
"sudo --user=maxscale valgrind -d "
"--log-file=/%s/valgrind%02d.log --trace-children=yes "
" --tool=callgrind --callgrind-out-file=/%s/callgrind%02d.log "
" /usr/bin/maxscale",
maxscale_log_dir[m], valgring_log_num,
maxscale_log_dir[m], valgring_log_num);
}
else
{
res = ssh_node_f(m, false,
"sudo --user=maxscale valgrind --leak-check=full --show-leak-kinds=all "
"--log-file=/%s/valgrind%02d.log --trace-children=yes "
"--track-origins=yes /usr/bin/maxscale", maxscale_log_dir[m], valgring_log_num);
}
valgring_log_num++;
}
else

View File

@ -20,7 +20,7 @@ public:
READCONN_SLAVE
};
Maxscales(const char *pref, const char *test_cwd, bool verbose, bool use_valgrind,
Maxscales(const char *pref, const char *test_cwd, bool verbose,
std::string network_config);
int read_env();
@ -338,6 +338,12 @@ public:
*/
bool use_valgrind;
/**
* @brief use_callgrind if true Maxscale will be executed under Valgrind with
* --callgrind option
*/
bool use_callgrind;
/**
* @brief valgring_log_num Counter for Maxscale restarts to avoid Valgrind log overwriting
*/

View File

@ -0,0 +1,20 @@
/**
* MXS-2450: Crash on COM_CHANGE_USER with disable_sescmd_history=true
* https://jira.mariadb.org/browse/MXS-2450
*/
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections test(argc, argv);
Connection conn = test.maxscales->rwsplit();
test.expect(conn.connect(), "Connection failed: %s", conn.error());
for (int i = 0; i < 10; i++)
{
test.expect(conn.reset_connection(), "Connection reset failed: %s", conn.error());
}
return test.global_result;
}

View File

@ -139,7 +139,6 @@ TestConnections::TestConnections(int argc, char* argv[])
, no_vm_revert(true)
, threads(4)
, use_ipv6(false)
, use_valgrind(false)
{
std::ios::sync_with_stdio(true);
signal_set(SIGSEGV, sigfatal_handler);
@ -387,7 +386,7 @@ TestConnections::TestConnections(int argc, char* argv[])
galera = NULL;
}
maxscales = new Maxscales("maxscale", test_dir, verbose, use_valgrind, network_config);
maxscales = new Maxscales("maxscale", test_dir, verbose, network_config);
bool maxscale_ok = maxscales->check_nodes();
bool repl_ok = no_repl || repl_future.get();
@ -517,7 +516,7 @@ TestConnections::~TestConnections()
// galera->disable_ssl();
}
if (use_valgrind)
if (maxscales->use_valgrind)
{
// stop all Maxscales to get proper Valgrind logs
for (int i = 0; i < maxscales->N; i++)
@ -680,7 +679,6 @@ void TestConnections::read_env()
revert_snapshot_command = readenv("revert_snapshot_command",
"mdbci snapshot revert --path-to-nodes %s --snapshot-name ", mdbci_config_name);
no_vm_revert = readenv_bool("no_vm_revert", true);
use_valgrind = readenv_bool("use_valgrind", false);
}
void TestConnections::print_env()
@ -1478,7 +1476,7 @@ int TestConnections::find_connected_slave1(int m)
int TestConnections::check_maxscale_processes(int m, int expected)
{
const char* ps_cmd = use_valgrind ?
const char* ps_cmd = maxscales->use_valgrind ?
"ps ax | grep valgrind | grep maxscale | grep -v grep | wc -l" :
"ps -C maxscale | grep maxscale | wc -l";

View File

@ -686,11 +686,6 @@ public:
*/
int call_mdbci(const char *options);
/**
* @brief use_valrind if true Maxscale will be executed under Valgrind
*/
bool use_valgrind;
/**
* @brief resinstall_maxscales Remove Maxscale form all nodes and installs new ones
* (to be used for run_test_snapshot)

View File

@ -203,7 +203,11 @@ void GaleraMonitor::update_server_status(MonitorServer* monitored_server)
" ('wsrep_cluster_state_uuid',"
" 'wsrep_cluster_size',"
" 'wsrep_local_index',"
" 'wsrep_local_state')";
" 'wsrep_local_state',"
" 'wsrep_desync',"
" 'wsrep_ready',"
" 'wsrep_sst_donor_rejects_queries',"
" 'wsrep_reject_queries')";
if (mxs_mysql_query(monitored_server->con, cluster_member) == 0
&& (result = mysql_store_result(monitored_server->con)) != NULL)
@ -270,6 +274,42 @@ void GaleraMonitor::update_server_status(MonitorServer* monitored_server)
info.local_state = atoi(row[1]);
}
/* Node is in desync - lets take it offline */
if (strcmp(row[0], "wsrep_desync") == 0)
{
if (strcasecmp(row[1],"YES") || strcasecmp(row[1],"ON") || strcasecmp(row[1],"1") || strcasecmp(row[1],"true"))
{
info.joined = 0;
}
}
/* Node rejects queries - lets take it offline */
if (strcmp(row[0], "wsrep_reject_queries") == 0)
{
if (strcasecmp(row[1],"ALL") || strcasecmp(row[1],"ALL_KILL"))
{
info.joined = 0;
}
}
/* Node rejects queries - lets take it offline */
if (strcmp(row[0], "wsrep_sst_donor_rejects_queries") == 0)
{
if (strcasecmp(row[1],"YES") || strcasecmp(row[1],"ON") || strcasecmp(row[1],"1") || strcasecmp(row[1],"true"))
{
info.joined = 0;
}
}
/* Node is not ready - lets take it offline */
if (strcmp(row[0], "wsrep_ready") == 0)
{
if (strcasecmp(row[1],"NO") || strcasecmp(row[1],"OFF") || strcasecmp(row[1],"0") || strcasecmp(row[1],"false"))
{
info.joined = 0;
}
}
if (strcmp(row[0], "wsrep_cluster_state_uuid") == 0 && row[1] && *row[1])
{
info.cluster_uuid = row[1];

View File

@ -608,7 +608,7 @@ bool RWSplitSession::route_session_write(GWBUF* querybuf, uint8_t command, uint3
return nsucc;
}
RWBackend* RWSplitSession::get_hinted_backend(char* name)
RWBackend* RWSplitSession::get_hinted_backend(const char* name)
{
RWBackend* rval = nullptr;
@ -669,15 +669,15 @@ RWBackend* RWSplitSession::get_last_used_backend()
*
* @param rses Pointer to router client session
* @param btype Backend type
* @param name Name of the backend which is primarily searched. May be NULL.
* @param name Name of the requested backend. May be NULL if any name is accepted.
* @param max_rlag Maximum replication lag
* @param target The target backend
*
* @return True if a backend was found
*/
RWBackend* RWSplitSession::get_target_backend(backend_type_t btype,
char* name,
int max_rlag)
const char* name,
int max_rlag)
{
/** Check whether using target_node as target SLAVE */
if (m_target_node && session_trx_is_read_only(m_client->session))
@ -686,13 +686,11 @@ RWBackend* RWSplitSession::get_target_backend(backend_type_t btype,
}
RWBackend* rval = nullptr;
if (name) /*< Choose backend by name from a hint */
if (name)
{
btype = BE_SLAVE;
// Choose backend by name from a hint
rval = get_hinted_backend(name);
}
else if (btype == BE_SLAVE)
{
rval = get_slave_backend(max_rlag);
@ -701,7 +699,6 @@ RWBackend* RWSplitSession::get_target_backend(backend_type_t btype,
{
rval = get_master_backend();
}
return rval;
}
@ -738,80 +735,72 @@ int RWSplitSession::get_max_replication_lag()
*/
RWBackend* RWSplitSession::handle_hinted_target(GWBUF* querybuf, route_target_t route_target)
{
char* named_server = NULL;
int rlag_max = SERVER::RLAG_UNDEFINED;
const char rlag_hint_tag[] = "max_slave_replication_lag";
const int comparelen = sizeof(rlag_hint_tag);
int config_max_rlag = get_max_replication_lag(); // From router configuration.
RWBackend* target = nullptr;
HINT* hint = querybuf->hint;
while (hint != NULL)
for (HINT* hint = querybuf->hint; !target && hint; hint = hint->next)
{
if (hint->type == HINT_ROUTE_TO_NAMED_SERVER)
{
/**
* Set the name of searched
* backend server.
*/
named_server = (char*)hint->data;
MXS_INFO("Hint: route to server '%s'", named_server);
}
else if (hint->type == HINT_PARAMETER
&& (strncasecmp((char*)hint->data,
"max_slave_replication_lag",
strlen("max_slave_replication_lag")) == 0))
{
int val = (int)strtol((char*)hint->value, (char**)NULL, 10);
if (val != 0 || errno == 0)
// Set the name of searched backend server.
const char* named_server = (char*)hint->data;
MXS_INFO("Hint: route to server '%s'.", named_server);
target = get_target_backend(BE_UNDEFINED, named_server, config_max_rlag);
if (!target)
{
/** Set max. acceptable replication lag value for backend srv */
rlag_max = val;
MXS_INFO("Hint: max_slave_replication_lag=%d", rlag_max);
// Target may differ from the requested name if the routing target is locked, e.g. by a trx.
// Target is null only if not locked and named server was not found or was invalid.
if (mxb_log_is_priority_enabled(LOG_INFO))
{
std::string status;
for (const auto& a : m_backends)
{
if (strcmp(a->server()->name(), named_server) == 0)
{
status = a->server()->status_string();
break;
}
}
MXS_INFO("Was supposed to route to named server %s but couldn't find the server in a "
"suitable state. Server state: %s",
named_server, !status.empty() ? status.c_str() : "Could not find server");
}
}
}
else if (hint->type == HINT_PARAMETER
&& (strncasecmp((char*)hint->data, rlag_hint_tag, comparelen) == 0))
{
const char* str_val = (char*)hint->value;
int hint_max_rlag = (int)strtol(str_val, (char**)NULL, 10);
if (hint_max_rlag != 0 || errno == 0)
{
MXS_INFO("Hint: %s=%d", rlag_hint_tag, hint_max_rlag);
target = get_target_backend(BE_SLAVE, nullptr, hint_max_rlag);
if (!target)
{
MXS_INFO("Was supposed to route to server with replication lag "
"at most %d but couldn't find such a slave.", hint_max_rlag);
}
}
else
{
MXS_ERROR("Hint: Could not parse value of %s: '%s' is not a valid number.",
rlag_hint_tag, str_val);
}
}
hint = hint->next;
} /*< while */
if (rlag_max == SERVER::RLAG_UNDEFINED) /*< no rlag max hint, use config */
{
rlag_max = get_max_replication_lag();
}
/** target may be master or slave */
backend_type_t btype = route_target & TARGET_SLAVE ? BE_SLAVE : BE_MASTER;
/**
* Search backend server by name or replication lag.
* If it fails, then try to find valid slave or master.
*/
RWBackend* target = get_target_backend(btype, named_server, rlag_max);
if (!target)
{
if (TARGET_IS_NAMED_SERVER(route_target))
{
std::string status = "Could not find server";
// If no target so far, pick any available. TODO: should this be error instead?
// Erroring here is more appropriate when namedserverfilter allows setting multiple target types
// e.g. target=server1,->slave
for (const auto& a : m_backends)
{
if (strcmp(a->server()->name(), named_server) == 0)
{
status = a->server()->status_string();
break;
}
}
MXS_INFO("Was supposed to route to named server %s but couldn't find the server in a "
"suitable state. Server state: %s", named_server, status.c_str());
}
else if (TARGET_IS_RLAG_MAX(route_target))
{
MXS_INFO("Was supposed to route to server with "
"replication lag at most %d but couldn't "
"find such a slave.",
rlag_max);
}
backend_type_t btype = route_target & TARGET_SLAVE ? BE_SLAVE : BE_MASTER;
target = get_target_backend(btype, NULL, config_max_rlag);
}
return target;
}

View File

@ -164,9 +164,10 @@ void RWSplitSession::process_sescmd_response(RWBackend* backend, GWBUF** ppPacke
*ppPacket = NULL;
}
if (m_expected_responses == 0
if (m_expected_responses == 0 && !m_config.disable_sescmd_history
&& (command == MXS_COM_CHANGE_USER || command == MXS_COM_RESET_CONNECTION))
{
mxb_assert_message(!m_sescmd_list.empty(), "Must have stored session commands");
mxb_assert_message(m_slave_responses.empty(), "All responses should've been processed");
// This is the last session command to finish that resets the session state, reset the history
MXS_INFO("Resetting session command history (length: %lu)", m_sescmd_list.size());

View File

@ -146,11 +146,11 @@ private:
void close_stale_connections();
int64_t get_current_rank();
mxs::RWBackend* get_hinted_backend(char* name);
mxs::RWBackend* get_hinted_backend(const char* name);
mxs::RWBackend* get_slave_backend(int max_rlag);
mxs::RWBackend* get_master_backend();
mxs::RWBackend* get_last_used_backend();
mxs::RWBackend* get_target_backend(backend_type_t btype, char* name, int max_rlag);
mxs::RWBackend* get_target_backend(backend_type_t btype, const char* name, int max_rlag);
bool handle_target_is_all(route_target_t route_target,
GWBUF* querybuf,