Remember if the current connection has an unknown transaction status

The fix for bug #1038 was to not return a connection to the connection pool if it has an error.
Although this is correct, it also has the side effect that connections coming
from connection pool and failing during the first query because the connection
was already broken, would be considered as possibly to run a transaction.
That is incorrect.

Now at connection level it is tracked if the transaction status is known or not.
pull/1464/head
René Cannaò 8 years ago committed by Nikolaos Vyzas
parent f13c4462ee
commit 7b3757a273

@ -92,6 +92,8 @@ class MySQL_Connection {
bool processing_prepared_statement_execute;
bool processing_multi_statement;
bool multiplex_delayed;
bool unknown_transaction_status;
void compute_unknown_transaction_status();
MySQL_Connection();
~MySQL_Connection();
bool set_autocommit(bool);

@ -942,6 +942,7 @@ int MySQL_Session::handler_again___status_PINGING_SERVER() {
int rc=myconn->async_ping(myds->revents);
if (rc==0) {
myconn->async_state_machine=ASYNC_IDLE;
myconn->unknown_transaction_status = false;
if (mysql_thread___multiplexing && (myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) {
myds->return_MySQL_Connection_To_Pool();
} else {
@ -2730,6 +2731,7 @@ handler_again:
enum session_status st=status;
size_t sts=previous_status.size();
if (sts) {
myconn->unknown_transaction_status = false;
myconn->async_state_machine=ASYNC_IDLE;
myds->DSS=STATE_MARIADB_GENERIC;
st=previous_status.top();
@ -2769,6 +2771,7 @@ handler_again:
if (mysql_thread___multiplexing && (myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) {
if (mysql_thread___connection_delay_multiplex_ms && mirror==false) {
myds->wait_until=thread->curtime+mysql_thread___connection_delay_multiplex_ms*1000;
myconn->unknown_transaction_status = false;
myconn->async_state_machine=ASYNC_IDLE;
myconn->multiplex_delayed=true;
myds->DSS=STATE_MARIADB_GENERIC;
@ -2796,6 +2799,7 @@ handler_again:
}
} else {
myconn->multiplex_delayed=false;
myconn->unknown_transaction_status = false;
myconn->async_state_machine=ASYNC_IDLE;
myds->DSS=STATE_MARIADB_GENERIC;
if (transaction_persistent==true) {
@ -2813,6 +2817,7 @@ handler_again:
} else {
if (rc==-1) {
int myerr=mysql_errno(myconn->mysql);
myconn->compute_unknown_transaction_status();
char *errmsg = NULL;
if (myerr == 0) {
if (CurrentQuery.mysql_stmt) {

@ -49,6 +49,29 @@ MySQL_Connection_userinfo::~MySQL_Connection_userinfo() {
if (schemaname) free(schemaname);
}
void MySQL_Connection::compute_unknown_transaction_status() {
if (mysql) {
int _myerrno=mysql_errno(mysql);
if (_myerrno == 0) {
unknown_transaction_status = false; // no error
return;
}
if (_myerrno >= 2000 && _myerrno < 3000) { // client error
// do not change it
return;
}
if (_myerrno >= 1000 && _myerrno < 2000) { // server error
unknown_transaction_status = true;
return;
}
if (_myerrno >= 3000 && _myerrno < 4000) { // server error
unknown_transaction_status = true;
return;
}
// all other cases, server error
}
}
uint64_t MySQL_Connection_userinfo::compute_hash() {
int l=0;
if (username)
@ -189,6 +212,7 @@ MySQL_Connection::MySQL_Connection() {
largest_query_length=0;
multiplex_delayed=false;
MyRS=NULL;
unknown_transaction_status = false;
creation_time=0;
processing_multi_statement=false;
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "Creating new MySQL_Connection %p\n", this);
@ -981,6 +1005,14 @@ handler_again:
}
break;
case ASYNC_QUERY_END:
if (mysql) {
int _myerrno=mysql_errno(mysql);
if (_myerrno == 0) {
unknown_transaction_status = false;
} else {
compute_unknown_transaction_status();
}
}
if (mysql_result) {
mysql_free_result(mysql_result);
mysql_result=NULL;
@ -1137,6 +1169,7 @@ int MySQL_Connection::async_connect(short event) {
return 0;
}
if (async_state_machine==ASYNC_CONNECT_SUCCESSFUL) {
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
myds->wait_until=0;
creation_time = monotonic_time();
@ -1145,6 +1178,7 @@ int MySQL_Connection::async_connect(short event) {
handler(event);
switch (async_state_machine) {
case ASYNC_CONNECT_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
myds->wait_until=0;
return 0;
@ -1224,8 +1258,10 @@ int MySQL_Connection::async_query(short event, char *stmt, unsigned long length,
if (async_state_machine==ASYNC_QUERY_END) {
if (mysql_errno(mysql)) {
compute_unknown_transaction_status();
return -1;
} else {
unknown_transaction_status = false;
return 0;
}
}
@ -1233,17 +1269,21 @@ int MySQL_Connection::async_query(short event, char *stmt, unsigned long length,
query.stmt_meta=NULL;
async_state_machine=ASYNC_QUERY_END;
if (mysql_stmt_errno(query.stmt)) {
compute_unknown_transaction_status();
return -1;
} else {
unknown_transaction_status = false;
return 0;
}
}
if (async_state_machine==ASYNC_STMT_PREPARE_SUCCESSFUL || async_state_machine==ASYNC_STMT_PREPARE_FAILED) {
query.stmt_meta=NULL;
if (async_state_machine==ASYNC_STMT_PREPARE_FAILED) {
compute_unknown_transaction_status();
return -1;
} else {
*_stmt=query.stmt;
unknown_transaction_status = false;
return 0;
}
}
@ -1273,6 +1313,7 @@ int MySQL_Connection::async_ping(short event) {
assert(ret_mysql);
switch (async_state_machine) {
case ASYNC_PING_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1292,6 +1333,7 @@ int MySQL_Connection::async_ping(short event) {
// check again
switch (async_state_machine) {
case ASYNC_PING_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1314,6 +1356,7 @@ int MySQL_Connection::async_change_user(short event) {
assert(ret_mysql);
switch (async_state_machine) {
case ASYNC_CHANGE_USER_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1333,6 +1376,7 @@ int MySQL_Connection::async_change_user(short event) {
// check again
switch (async_state_machine) {
case ASYNC_CHANGE_USER_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1355,6 +1399,7 @@ int MySQL_Connection::async_select_db(short event) {
assert(ret_mysql);
switch (async_state_machine) {
case ASYNC_INITDB_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1371,6 +1416,7 @@ int MySQL_Connection::async_select_db(short event) {
// check again
switch (async_state_machine) {
case ASYNC_INITDB_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1390,6 +1436,7 @@ int MySQL_Connection::async_set_autocommit(short event, bool ac) {
assert(ret_mysql);
switch (async_state_machine) {
case ASYNC_SET_AUTOCOMMIT_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1407,6 +1454,7 @@ int MySQL_Connection::async_set_autocommit(short event, bool ac) {
// check again
switch (async_state_machine) {
case ASYNC_SET_AUTOCOMMIT_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1426,6 +1474,7 @@ int MySQL_Connection::async_set_names(short event, uint8_t c) {
assert(ret_mysql);
switch (async_state_machine) {
case ASYNC_SET_NAMES_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1443,6 +1492,7 @@ int MySQL_Connection::async_set_names(short event, uint8_t c) {
// check again
switch (async_state_machine) {
case ASYNC_SET_NAMES_SUCCESSFUL:
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
break;
@ -1487,6 +1537,7 @@ void MySQL_Connection::async_free_result() {
mysql_result=NULL;
}
}
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
if (MyRS) {
delete MyRS;
@ -1499,7 +1550,7 @@ bool MySQL_Connection::IsActiveTransaction() {
bool ret=false;
if (mysql) {
ret = (mysql->server_status & SERVER_STATUS_IN_TRANS);
if (ret == false && (mysql)->net.last_errno) {
if (ret == false && (mysql)->net.last_errno && unknown_transaction_status == true) {
ret = true;
}
if (ret == false) {
@ -1685,8 +1736,10 @@ int MySQL_Connection::async_send_simple_command(short event, char *stmt, unsigne
}
if (async_state_machine==ASYNC_QUERY_END) {
if (mysql_errno(mysql)) {
compute_unknown_transaction_status();
return -1;
} else {
unknown_transaction_status = false;
async_state_machine=ASYNC_IDLE;
return 0;
}

Loading…
Cancel
Save