Merge branch '2.3' into 2.4
This commit is contained in:
@ -51,8 +51,7 @@ export sshopt="$scpopt $sshuser@$IP"
|
|||||||
|
|
||||||
old_version=`ssh $sshopt "maxscale --version" `
|
old_version=`ssh $sshopt "maxscale --version" `
|
||||||
|
|
||||||
${mdbci_dir}/mdbci setup_repo --product maxscale_ci --product-version ${target} $name/maxscale
|
${mdbci_dir}/mdbci install_product --product maxscale_ci --product-version ${target} $name/maxscale
|
||||||
${mdbci_dir}/mdbci install_product --product maxscale_ci $name/maxscale
|
|
||||||
|
|
||||||
res=$?
|
res=$?
|
||||||
|
|
||||||
|
|||||||
@ -140,14 +140,15 @@ typedef enum
|
|||||||
*/
|
*/
|
||||||
typedef struct mysql_session
|
typedef struct mysql_session
|
||||||
{
|
{
|
||||||
uint8_t client_sha1[MYSQL_SCRAMBLE_LEN]; /*< SHA1(password) */
|
uint8_t client_sha1[MYSQL_SCRAMBLE_LEN]; /*< SHA1(password) */
|
||||||
char user[MYSQL_USER_MAXLEN + 1]; /*< username */
|
char user[MYSQL_USER_MAXLEN + 1]; /*< username */
|
||||||
char db[MYSQL_DATABASE_MAXLEN + 1]; /*< database */
|
char db[MYSQL_DATABASE_MAXLEN + 1]; /*< database */
|
||||||
int auth_token_len; /*< token length */
|
int auth_token_len; /*< token length */
|
||||||
uint8_t* auth_token; /*< token */
|
uint8_t* auth_token; /*< token */
|
||||||
bool correct_authenticator; /*< is session using mysql_native_password? */
|
bool correct_authenticator; /*< is session using mysql_native_password? */
|
||||||
uint8_t next_sequence; /*< Next packet sequence */
|
uint8_t next_sequence; /*< Next packet sequence */
|
||||||
bool auth_switch_sent; /*< Expecting a response to AuthSwitchRequest? */
|
bool auth_switch_sent; /*< Expecting a response to AuthSwitchRequest? */
|
||||||
|
bool changing_user; /*< True if a COM_CHANGE_USER is in progress */
|
||||||
} MYSQL_session;
|
} MYSQL_session;
|
||||||
|
|
||||||
/** Protocol packing macros. */
|
/** Protocol packing macros. */
|
||||||
|
|||||||
@ -233,6 +233,16 @@ public:
|
|||||||
return m_reply_state == REPLY_STATE_DONE;
|
return m_reply_state == REPLY_STATE_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a partial response has been received from the backend
|
||||||
|
*
|
||||||
|
* @return True if some parts of the reply have been received
|
||||||
|
*/
|
||||||
|
bool reply_has_started() const
|
||||||
|
{
|
||||||
|
return m_reply_state != REPLY_STATE_START && m_reply_state != REPLY_STATE_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
void process_packets(GWBUF* buffer);
|
void process_packets(GWBUF* buffer);
|
||||||
|
|
||||||
// Controlled by the session
|
// Controlled by the session
|
||||||
|
|||||||
@ -56,7 +56,7 @@ port = 4009
|
|||||||
[throttle]
|
[throttle]
|
||||||
type = filter
|
type = filter
|
||||||
module = throttlefilter
|
module = throttlefilter
|
||||||
max_qps = 1000
|
max_qps = 500
|
||||||
throttling_duration = 10000
|
throttling_duration = 10000
|
||||||
sampling_duration = 250
|
sampling_duration = 250
|
||||||
continuous_duration = 2000
|
continuous_duration = 2000
|
||||||
|
|||||||
@ -15,7 +15,7 @@ DEFINE_EXCEPTION(Whoopsy);
|
|||||||
|
|
||||||
// TODO these should be read from maxscale.cnf. Maybe the test-lib should replace
|
// TODO these should be read from maxscale.cnf. Maybe the test-lib should replace
|
||||||
// any "###ENV_VAR###", with environment variables so that code and conf can share.
|
// any "###ENV_VAR###", with environment variables so that code and conf can share.
|
||||||
constexpr int max_qps = 1000;
|
constexpr int max_qps = 500;
|
||||||
constexpr float throttling_duration = 10000 / 1000.0;
|
constexpr float throttling_duration = 10000 / 1000.0;
|
||||||
constexpr float sampling_duration = 250 / 1000.0;
|
constexpr float sampling_duration = 250 / 1000.0;
|
||||||
constexpr float continuous_duration = 2000 / 1000.0;
|
constexpr float continuous_duration = 2000 / 1000.0;
|
||||||
@ -132,7 +132,7 @@ void gauge_raw_speed(TestConnections& test)
|
|||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "The raw speed is too slow, " << rs.qps
|
os << "The raw speed is too slow, " << rs.qps
|
||||||
<< "qps, compared to max_qps = " << max_qps << "qps for accurate testing.";
|
<< "qps, compared to max_qps = " << max_qps << "qps for accurate testing.";
|
||||||
test.add_result(1, "%s", os.str().c_str());
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,8 @@ void run_test(TestConnections& test, TestCase test_case)
|
|||||||
|
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
test.expect(mysql_query(test.maxscales->conn_rwsplit[0], "SELECT 1") == 0, "Normal queries should work");
|
test.expect(mysql_query(test.maxscales->conn_rwsplit[0], "SELECT 1") == 0,
|
||||||
|
"Normal queries should work: %s", mysql_error(test.maxscales->conn_rwsplit[0]));
|
||||||
|
|
||||||
test.maxscales->disconnect();
|
test.maxscales->disconnect();
|
||||||
}
|
}
|
||||||
@ -79,6 +80,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
test.try_query(test.maxscales->conn_rwsplit[0], "COMMIT");
|
test.try_query(test.maxscales->conn_rwsplit[0], "COMMIT");
|
||||||
test.maxscales->disconnect();
|
test.maxscales->disconnect();
|
||||||
|
test.repl->sync_slaves();
|
||||||
|
|
||||||
vector<TestCase> tests =
|
vector<TestCase> tests =
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
sudo service maxscale stop
|
sudo systemctl stop maxscale || sudo service maxscale stop
|
||||||
|
|
||||||
hm=`pwd`
|
hm=`pwd`
|
||||||
$hm/start_killer.sh &
|
$hm/start_killer.sh &
|
||||||
|
|||||||
@ -2348,12 +2348,6 @@ int TestConnections::reinstall_maxscales()
|
|||||||
maxscales->ssh_node(i, "yum remove maxscale -y", true);
|
maxscales->ssh_node(i, "yum remove maxscale -y", true);
|
||||||
maxscales->ssh_node(i, "yum clean all", true);
|
maxscales->ssh_node(i, "yum clean all", true);
|
||||||
|
|
||||||
sprintf(sys, "mdbci setup_repo --product maxscale_ci --product-version %s %s/%s_%03d",
|
|
||||||
target, mdbci_config_name, maxscales->prefix, i);
|
|
||||||
if (system(sys))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
sprintf(sys, "mdbci install_product --product maxscale_ci --product-version %s %s/%s_%03d",
|
sprintf(sys, "mdbci install_product --product maxscale_ci --product-version %s %s/%s_%03d",
|
||||||
target, mdbci_config_name, maxscales->prefix, i);
|
target, mdbci_config_name, maxscales->prefix, i);
|
||||||
if (system(sys))
|
if (system(sys))
|
||||||
|
|||||||
@ -994,6 +994,9 @@ QueryClassifier::RouteInfo QueryClassifier::update_route_info(
|
|||||||
uint32_t type_mask = QUERY_TYPE_UNKNOWN;
|
uint32_t type_mask = QUERY_TYPE_UNKNOWN;
|
||||||
uint32_t stmt_id = 0;
|
uint32_t stmt_id = 0;
|
||||||
|
|
||||||
|
// Reset for every classification
|
||||||
|
m_ps_continuation = false;
|
||||||
|
|
||||||
// TODO: It may be sufficient to simply check whether we are in a read-only
|
// TODO: It may be sufficient to simply check whether we are in a read-only
|
||||||
// TODO: transaction.
|
// TODO: transaction.
|
||||||
bool in_read_only_trx =
|
bool in_read_only_trx =
|
||||||
|
|||||||
@ -448,6 +448,8 @@ bool mxs_worker_should_shutdown(MXB_WORKER* pWorker)
|
|||||||
|
|
||||||
RoutingWorker* RoutingWorker::get(int worker_id)
|
RoutingWorker* RoutingWorker::get(int worker_id)
|
||||||
{
|
{
|
||||||
|
mxb_assert(this_unit.initialized);
|
||||||
|
|
||||||
if (worker_id == MAIN)
|
if (worker_id == MAIN)
|
||||||
{
|
{
|
||||||
worker_id = this_unit.id_main_worker;
|
worker_id = this_unit.id_main_worker;
|
||||||
|
|||||||
@ -918,6 +918,9 @@ static int gw_read_and_write(DCB* dcb)
|
|||||||
*/
|
*/
|
||||||
GWBUF_DATA(read_buffer)[3] = 0x3;
|
GWBUF_DATA(read_buffer)[3] = 0x3;
|
||||||
proto->changing_user = false;
|
proto->changing_user = false;
|
||||||
|
|
||||||
|
auto s = (MYSQL_session*)session->client_dcb->data;
|
||||||
|
s->changing_user = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1718,7 +1718,15 @@ static int gw_client_hangup_event(DCB* dcb)
|
|||||||
errmsg += ": " + extra;
|
errmsg += ": " + extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
modutil_send_mysql_err_packet(dcb, 0, 0, 1927, "08S01", errmsg.c_str());
|
int seqno = 1;
|
||||||
|
|
||||||
|
if (dcb->data && ((MYSQL_session*)dcb->data)->changing_user)
|
||||||
|
{
|
||||||
|
// In case a COM_CHANGE_USER is in progress, we need to send the error with the seqno 3
|
||||||
|
seqno = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
modutil_send_mysql_err_packet(dcb, seqno, 0, 1927, "08S01", errmsg.c_str());
|
||||||
}
|
}
|
||||||
dcb_close(dcb);
|
dcb_close(dcb);
|
||||||
}
|
}
|
||||||
@ -1921,6 +1929,10 @@ static int route_by_statement(MXS_SESSION* session, uint64_t capabilities, GWBUF
|
|||||||
|
|
||||||
if (!proto->changing_user && proto->current_command == MXS_COM_CHANGE_USER)
|
if (!proto->changing_user && proto->current_command == MXS_COM_CHANGE_USER)
|
||||||
{
|
{
|
||||||
|
// Track the COM_CHANGE_USER progress at the session level
|
||||||
|
auto s = (MYSQL_session*)session->client_dcb->data;
|
||||||
|
s->changing_user = true;
|
||||||
|
|
||||||
changed_user = true;
|
changed_user = true;
|
||||||
send_auth_switch_request_packet(session->client_dcb);
|
send_auth_switch_request_packet(session->client_dcb);
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ uint8_t null_client_sha1[MYSQL_SCRAMBLE_LEN] = "";
|
|||||||
MYSQL_session* mysql_session_alloc()
|
MYSQL_session* mysql_session_alloc()
|
||||||
{
|
{
|
||||||
MYSQL_session* ses = (MYSQL_session*)MXS_CALLOC(1, sizeof(MYSQL_session));
|
MYSQL_session* ses = (MYSQL_session*)MXS_CALLOC(1, sizeof(MYSQL_session));
|
||||||
|
ses->changing_user = false;
|
||||||
return ses;
|
return ses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,6 +96,14 @@ bool RWBackend::write(GWBUF* buffer, response_type type)
|
|||||||
|
|
||||||
if (mxs_mysql_is_ps_command(cmd))
|
if (mxs_mysql_is_ps_command(cmd))
|
||||||
{
|
{
|
||||||
|
// We need to completely separate the buffer this backend owns and the one that the caller owns to
|
||||||
|
// prevent any modifications from affecting the one that was written through this backend. If the
|
||||||
|
// buffer gets placed into the write queue of the DCB, subsequent modifications to the original buffer
|
||||||
|
// would be propagated to the one this backend owns.
|
||||||
|
GWBUF* tmp = gwbuf_deep_clone(buffer);
|
||||||
|
gwbuf_free(buffer);
|
||||||
|
buffer = tmp;
|
||||||
|
|
||||||
uint32_t id = mxs_mysql_extract_ps_id(buffer);
|
uint32_t id = mxs_mysql_extract_ps_id(buffer);
|
||||||
BackendHandleMap::iterator it = m_ps_handles.find(id);
|
BackendHandleMap::iterator it = m_ps_handles.find(id);
|
||||||
|
|
||||||
|
|||||||
@ -235,12 +235,7 @@ bool RWSplitSession::route_single_stmt(GWBUF* querybuf)
|
|||||||
|
|
||||||
RWBackend* target = nullptr;
|
RWBackend* target = nullptr;
|
||||||
|
|
||||||
if (command == MXS_COM_STMT_EXECUTE && stmt_id == 0)
|
if (TARGET_IS_ALL(route_target))
|
||||||
{
|
|
||||||
// Unknown prepared statement ID
|
|
||||||
succp = send_unknown_ps_error(extract_binary_ps_id(querybuf));
|
|
||||||
}
|
|
||||||
else if (TARGET_IS_ALL(route_target))
|
|
||||||
{
|
{
|
||||||
succp = handle_target_is_all(route_target, querybuf, command, qtype);
|
succp = handle_target_is_all(route_target, querybuf, command, qtype);
|
||||||
}
|
}
|
||||||
@ -282,6 +277,11 @@ bool RWSplitSession::route_single_stmt(GWBUF* querybuf)
|
|||||||
target = m_prev_target;
|
target = m_prev_target;
|
||||||
succp = true;
|
succp = true;
|
||||||
}
|
}
|
||||||
|
else if (mxs_mysql_is_ps_command(command) && stmt_id == 0)
|
||||||
|
{
|
||||||
|
// Unknown prepared statement ID
|
||||||
|
succp = send_unknown_ps_error(extract_binary_ps_id(querybuf));
|
||||||
|
}
|
||||||
else if (TARGET_IS_NAMED_SERVER(route_target) || TARGET_IS_RLAG_MAX(route_target))
|
else if (TARGET_IS_NAMED_SERVER(route_target) || TARGET_IS_RLAG_MAX(route_target))
|
||||||
{
|
{
|
||||||
if ((target = handle_hinted_target(querybuf, route_target)))
|
if ((target = handle_hinted_target(querybuf, route_target)))
|
||||||
|
|||||||
@ -985,6 +985,18 @@ void RWSplitSession::handleError(GWBUF* errmsgbuf,
|
|||||||
RWBackend* backend = get_backend_from_dcb(problem_dcb);
|
RWBackend* backend = get_backend_from_dcb(problem_dcb);
|
||||||
mxb_assert(backend->in_use());
|
mxb_assert(backend->in_use());
|
||||||
|
|
||||||
|
if (backend->reply_has_started())
|
||||||
|
{
|
||||||
|
MXS_ERROR("Server '%s' was lost in the middle of a resultset, cannot continue the session: %s",
|
||||||
|
backend->name(), extract_error(errmsgbuf).c_str());
|
||||||
|
|
||||||
|
// This effectively causes an instant termination of the client connection and prevents any errors
|
||||||
|
// from being sent to the client (MXS-2562).
|
||||||
|
dcb_close(m_client);
|
||||||
|
*succp = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case ERRACT_NEW_CONNECTION:
|
case ERRACT_NEW_CONNECTION:
|
||||||
|
|||||||
Reference in New Issue
Block a user