Switching autocommit from 0 to 1 drops SAVEPOINTs

Another edge case due to MySQL bug https://bugs.mysql.com/bug.php?id=107875
related to autocommit=0 and SAVEPOINT
pull/3916/head
René Cannaò 4 years ago
parent f7d8824379
commit 622b748fdf

@ -311,7 +311,7 @@ class MySQL_Session
unsigned int NumActiveTransactions(bool check_savpoint=false);
bool HasOfflineBackends();
bool SetEventInOfflineBackends();
int FindOneActiveTransaction();
int FindOneActiveTransaction(bool check_savepoint=false);
unsigned long long IdleTime();
void reset_all_backends();

@ -830,7 +830,7 @@ bool MySQL_Session::handler_CommitRollback(PtrSize_t *pkt) {
if (ret==false) {
return false; // quick exit
}
// this is the only part of the code (as at release 2.4.3) where we call
// in this part of the code (as at release 2.4.3) where we call
// NumActiveTransactions() with the check_savepoint flag .
// This to try to handle MySQL bug https://bugs.mysql.com/bug.php?id=107875
unsigned int nTrx=NumActiveTransactions(true);
@ -953,12 +953,16 @@ bool MySQL_Session::handler_SetAutocommit(PtrSize_t *pkt) {
goto __ret_autocommit_OK;
}
if (fd==1 && autocommit==false) {
if (nTrx) {
// in this part of the code (as at release 2.4.3) where we call
// NumActiveTransactions() with the check_savepoint flag .
// This to try to handle MySQL bug https://bugs.mysql.com/bug.php?id=107875
unsigned int nTrx_SP=NumActiveTransactions(true); // check savepoint
if (nTrx_SP) { // previously we were checking nTrx . Now nTrx_SP
// there is an active transaction, we need to forward it
// because this can potentially close the transaction
autocommit=true;
client_myds->myconn->set_autocommit(autocommit);
autocommit_on_hostgroup=FindOneActiveTransaction();
autocommit_on_hostgroup=FindOneActiveTransaction(true);
free(_new_pkt.ptr);
sending_set_autocommit=true;
return false;
@ -1897,6 +1901,12 @@ bool MySQL_Session::handler_again___verify_backend_autocommit() {
MySQL_Connection *mc = mybe->server_myds->myconn;
mc->set_autocommit(autocommit);
mc->options.last_set_autocommit = ( mc->options.autocommit ? 1 : 0 );
if (autocommit==1) {
// due to MySQL bug https://bugs.mysql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0 , if we send autocommit=1 we need to drop
// the flag related to savepoint
mc->set_status(false, STATUS_MYSQL_CONNECTION_HAS_SAVEPOINT);
}
return false;
}
proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Session %p , client: %d , backend: %d\n", this, client_myds->myconn->options.autocommit, mybe->server_myds->myconn->options.autocommit);
@ -7035,17 +7045,29 @@ bool MySQL_Session::SetEventInOfflineBackends() {
return ret;
}
int MySQL_Session::FindOneActiveTransaction() {
int MySQL_Session::FindOneActiveTransaction(bool check_savepoint) {
int ret=-1;
if (mybes==0) return ret;
MySQL_Backend *_mybe;
unsigned int i;
for (i=0; i < mybes->len; i++) {
_mybe=(MySQL_Backend *)mybes->index(i);
if (_mybe->server_myds)
if (_mybe->server_myds->myconn)
if (_mybe->server_myds->myconn->IsActiveTransaction())
if (_mybe->server_myds) {
if (_mybe->server_myds->myconn) {
if (_mybe->server_myds->myconn->IsActiveTransaction()) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
} else {
// we use check_savepoint to check if we shouldn't ignore COMMIT or ROLLBACK due
// to MySQL bug https://bugs.mysql.com/bug.php?id=107875 related to
// SAVEPOINT and autocommit=0
if (check_savepoint) {
if (_mybe->server_myds->myconn->AutocommitFalse_AndSavepoint() == true) {
return (int)_mybe->server_myds->myconn->parent->myhgc->hid;
}
}
}
}
}
}
return ret;
}

@ -19,37 +19,19 @@
#include "utils.h"
#include "command_line.h"
#include "json.hpp"
using nlohmann::json;
unsigned long long monotonic_time() {
struct timespec ts;
//clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); // this is faster, but not precise
clock_gettime(CLOCK_MONOTONIC, &ts);
return (((unsigned long long) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000);
}
struct cpu_timer
{
cpu_timer() {
begin = monotonic_time();
}
~cpu_timer()
{
unsigned long long end = monotonic_time();
std::cerr << double( end - begin ) / 1000000 << " secs.\n" ;
begin=end-begin;
};
unsigned long long begin;
};
bool debug_diag=true;
/*
unsigned int num_threads=4;
int count=10;
int transactions=200;
*/
/*
unsigned int num_threads=1;
int count=1;
int transactions=200;
int transactions=5;
*/
char *username=NULL;
char *password=NULL;
char *host=(char *)"localhost";
@ -97,6 +79,7 @@ void * my_conn_thread(void *arg) {
unsigned int select_ERR=0;
int i, j;
MYSQL **mysqlconns=(MYSQL **)malloc(sizeof(MYSQL *)*count);
bool ac[count];
if (mysqlconns==NULL) {
exit(EXIT_FAILURE);
@ -118,6 +101,7 @@ void * my_conn_thread(void *arg) {
}
mysqlconns[i]=mysql;
__sync_add_and_fetch(&status_connections,1);
ac[i]=true;
}
__sync_fetch_and_add(&connect_phase_completed,1);
@ -135,6 +119,11 @@ void * my_conn_thread(void *arg) {
int sleepDelay;
for (int i=0; i<fr%3; i++) {
std::string q = "SET autocommit=" + std::to_string(fr%2);
if (fr%2 == 0) {
ac[r1]=false;
} else {
ac[r1]=true;
}
if (debug_diag==true)
diag("Thread %lu , connection %p , query: %s", pthread_self(), mysql, q.c_str());
if (mysql_query(mysql, q.c_str())) {
@ -153,6 +142,7 @@ void * my_conn_thread(void *arg) {
diag("Thread %lu , connection %p , query: %s", pthread_self(), mysql, q.c_str());
} else {
q = "SET AUTOCOMMIT=0";
ac[r1]=false;
if (debug_diag==true)
diag("Thread %lu , connection %p , query: %s", pthread_self(), mysql, q.c_str());
}
@ -169,7 +159,7 @@ void * my_conn_thread(void *arg) {
fprintf(stderr,"Error running query: %s. Error: %s\n", sel1.c_str(), mysql_error(mysql));
} else {
if (debug_diag==true)
diag("Thread %lu , connection %p , query: %s", pthread_self(), mysql, sel1.c_str());
diag("Thread %lu , connection %p , query: %s. QOT: %s", pthread_self(), mysql, sel1.c_str(), (explicit_transaction==false ? "true" : "false"));
MYSQL_RES *result = mysql_store_result(mysql);
mysql_free_result(result);
select_OK++;
@ -250,10 +240,26 @@ void * my_conn_thread(void *arg) {
{
std::string q;
int f = fr%3;
switch (f) {
case 0:
q = "COMMIT";
break;
case 1:
q = "ROLLBACK";
break;
case 2:
if (ac[r1] == false) {
q = "SET autocommit=1";
} else {
q = "COMMIT";
}
break;
/*
if (f==0) {
q = "COMMIT";
} else {
q = "ROLLBACK";
*/
/*
// FIXME: this code is currently commented because of another bug
if (explicit_transaction==false) {
@ -263,6 +269,8 @@ void * my_conn_thread(void *arg) {
}
*/
}
if (debug_diag==true)
diag("Thread %lu , connection %p , query: %s, TrxEnd", pthread_self(), mysql, q.c_str());
if (mysql_query(mysql, q.c_str())) {
fprintf(stderr,"Error running query: %s. Error: %s\n", q.c_str(), mysql_error(mysql));
exit(EXIT_FAILURE);
@ -450,6 +458,9 @@ int main(int argc, char *argv[]) {
// FIXME: until we fix the autocommit bug, we may have some minor mismatch
//ok((MyHGM_myconnpoll_get <= cnt_transactions+cnt_SELECT_outside_transactions && MyHGM_myconnpoll_get >= cnt_transactions+cnt_SELECT_outside_transactions-10) , "Number of transactions [%d] , Queries outside transaction [%d] , total connections returned [%d]", cnt_transactions.load(std::memory_order_relaxed), cnt_SELECT_outside_transactions.load(std::memory_order_relaxed), MyHGM_myconnpoll_get);
ok((MyHGM_myconnpoll_get == cnt_transactions+cnt_SELECT_outside_transactions) , "Number of transactions [%d] , Queries outside transaction [%d] , total connections returned [%d]", cnt_transactions.load(std::memory_order_relaxed), cnt_SELECT_outside_transactions.load(std::memory_order_relaxed), MyHGM_myconnpoll_get);
MYSQL_QUERY(mysqladmin, "DELETE FROM mysql_query_rules");
MYSQL_QUERY(mysqladmin, "INSERT INTO mysql_query_rules SELECT * FROM mysql_query_rules_948");
MYSQL_QUERY(mysqladmin, "LOAD MYSQL QUERY RULES TO RUNTIME");

Loading…
Cancel
Save