diff --git a/include/mysql_connection.h b/include/mysql_connection.h index 20b8b2b46..166bc265f 100644 --- a/include/mysql_connection.h +++ b/include/mysql_connection.h @@ -33,9 +33,11 @@ class MySQL_Connection { unsigned long long inserted_into_pool; public: int fd; + short wait_events; + unsigned long long timeout; char scramble_buff[40]; int async_exit_status; // exit status of MariaDB Client Library Non blocking API - int async_state_machine; // Async state machine + MDB_ASYNC_ST async_state_machine; // Async state machine MYSQL *mysql; MYSQL *ret_mysql; struct { @@ -76,5 +78,8 @@ class MySQL_Connection { bool get_status_prepared_statement(); bool get_status_user_variable(); void connect_start(); + void connect_cont(short event); + MDB_ASYNC_ST handler(short event); + void next_event(MDB_ASYNC_ST new_st); }; #endif /* __CLASS_MYSQL_CONNECTION_H */ diff --git a/include/proxysql_structs.h b/include/proxysql_structs.h index c834a614a..cfe4c9523 100644 --- a/include/proxysql_structs.h +++ b/include/proxysql_structs.h @@ -11,6 +11,14 @@ enum cred_username_type { USERNAME_BACKEND, USERNAME_FRONTEND }; +enum MDB_ASYNC_ST { // MariaDB Async State Machine + ASYNC_CONNECT_START, + ASYNC_CONNECT_CONT, + ASYNC_CONNECT_END, + ASYNC_CONNECT_SUCCESSFUL, + ASYNC_CONNECT_FAILED +}; + // list of possible debugging modules enum debug_module { PROXY_DEBUG_GENERIC, diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index cfbb908ee..c3c6be110 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -6,7 +6,6 @@ extern Query_Cache *GloQC; extern ProxySQL_Admin *GloAdmin; extern MySQL_Threads_Handler *GloMTH; - Query_Info::Query_Info() { MyComQueryCmd=MYSQL_COM_QUERY___NONE; QueryPointer=NULL; @@ -447,16 +446,19 @@ __exit_DSS__STATE_NOT_INITIALIZED: if (mybe->server_myds->DSS > STATE_MARIADB_BEGIN && mybe->server_myds->DSS < STATE_MARIADB_END) { MySQL_Data_Stream *myds=mybe->server_myds; MySQL_Connection *myconn=mybe->server_myds->myconn; - int ms_status = 0; +// int ms_status = 0; switch (status) { case CONNECTING_SERVER: - if (myds->revents & POLLIN) ms_status |= MYSQL_WAIT_READ; - if (myds->revents & POLLOUT) ms_status |= MYSQL_WAIT_WRITE; - if (myds->revents & POLLPRI) ms_status |= MYSQL_WAIT_EXCEPT; - if (ms_status) { - myconn->async_exit_status = mysql_real_connect_cont(&myconn->ret_mysql, myconn->mysql, ms_status); - if (myconn->async_exit_status==0) { +// if (myds->revents & POLLIN) ms_status |= MYSQL_WAIT_READ; +// if (myds->revents & POLLOUT) ms_status |= MYSQL_WAIT_WRITE; +// if (myds->revents & POLLPRI) ms_status |= MYSQL_WAIT_EXCEPT; +// if (ms_status) { + if (myds->revents) { + myconn->handler(myds->revents); +// myconn->async_exit_status = mysql_real_connect_cont(&myconn->ret_mysql, myconn->mysql, ms_status); +// if (myconn->async_exit_status==0) { if (myconn->ret_mysql) { + if (myconn->async_state_machine==ASYNC_CONNECT_SUCCESSFUL) { myds->myds_type=MYDS_BACKEND; myds->DSS=STATE_READY; //mybe->myconn=server_myds->myconn; @@ -468,9 +470,12 @@ __exit_DSS__STATE_NOT_INITIALIZED: myds->PSarrayOUT->add(pkt2.ptr, pkt2.size); myds->DSS=STATE_QUERY_SENT_DS; } + } else { + assert(0); + } //assert(0); } - } +// } } break; default: @@ -1293,21 +1298,29 @@ void MySQL_Session::handler___client_DSS_QUERY_SENT___server_DSS_NOT_INITIALIZED proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 5, "Sess=%p -- MySQL Connection has no FD\n", this); int __fd; MySQL_Connection *myconn=mybe->server_myds->myconn; - myconn->mysql=mysql_init(NULL); - assert(myconn->mysql); - mysql_options(myconn->mysql, MYSQL_OPT_NONBLOCK, 0); +// myconn->mysql=mysql_init(NULL); +// assert(myconn->mysql); +// mysql_options(myconn->mysql, MYSQL_OPT_NONBLOCK, 0); myconn->userinfo->set(client_myds->myconn->userinfo); // FIXME: set client_flags //mybe->server_myds->myconn->connect_start(); //mybe->server_myds->fd=myconn->fd; - + //myconn->connect_start(); + myconn->handler(0); +/* if (myconn->parent->port) { myconn->async_exit_status=mysql_real_connect_start(&myconn->ret_mysql,myconn->mysql, myconn->parent->address, myconn->userinfo->username, myconn->userinfo->password, myconn->userinfo->schemaname, myconn->parent->port, NULL, 0); } else { myconn->async_exit_status=mysql_real_connect_start(&myconn->ret_mysql,myconn->mysql, "localhost", myconn->userinfo->username, myconn->userinfo->password, myconn->userinfo->schemaname, myconn->parent->port, myconn->parent->address, 0); } myconn->fd=mysql_get_socket(myconn->mysql); + if (myconn->async_exit_status) { +// myconn->async_state_machine=1; + } else { +// myconn->async_state_machine=2; + } +*/ mybe->server_myds->fd=myconn->fd; mybe->server_myds->DSS=STATE_MARIADB_CONNECTING; status=CONNECTING_SERVER; diff --git a/lib/mysql_connection.cpp b/lib/mysql_connection.cpp index 5d6c22ae5..95182748f 100644 --- a/lib/mysql_connection.cpp +++ b/lib/mysql_connection.cpp @@ -14,6 +14,20 @@ void MySQL_Connection::operator delete(void *ptr) { //extern __thread char *mysql_thread___default_schema; +static int +mysql_status(short event) { + int status= 0; + if (event & POLLIN) + status|= MYSQL_WAIT_READ; + if (event & POLLOUT) + status|= MYSQL_WAIT_WRITE; +// FIXME: handle timeout +// if (event & PROXY_TIMEOUT) +// status|= MYSQL_WAIT_TIMEOUT; + return status; +} + + MySQL_Connection_userinfo::MySQL_Connection_userinfo() { username=NULL; password=NULL; @@ -102,6 +116,7 @@ bool MySQL_Connection_userinfo::set_schemaname(char *_new, int l) { MySQL_Connection::MySQL_Connection() { //memset(&myconn,0,sizeof(MYSQL)); mysql=NULL; + async_state_machine=ASYNC_CONNECT_START; ret_mysql=NULL; myds=NULL; inserted_into_pool=0; @@ -201,6 +216,9 @@ bool MySQL_Connection::get_status_prepared_statement() { // non blocking API void MySQL_Connection::connect_start() { + mysql=mysql_init(NULL); + assert(mysql); + mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0); if (parent->port) { async_exit_status=mysql_real_connect_start(&ret_mysql, mysql, parent->address, userinfo->username, userinfo->password, userinfo->schemaname, parent->port, NULL, 0); } else { @@ -209,3 +227,83 @@ void MySQL_Connection::connect_start() { fd=mysql_get_socket(mysql); } +void MySQL_Connection::connect_cont(short event) { + async_exit_status = mysql_real_connect_cont(&ret_mysql, mysql, mysql_status(event)); +} + +#define NEXT_IMMEDIATE(new_st) do { async_state_machine = new_st; goto handler_again; } while (0) + +MDB_ASYNC_ST MySQL_Connection::handler(short event) { + if (mysql==NULL) { + // it is the first time handler() is being called + async_state_machine=ASYNC_CONNECT_START; + } +handler_again: + switch (async_state_machine) { + case ASYNC_CONNECT_START: + connect_start(); + if (async_exit_status) { + next_event(ASYNC_CONNECT_CONT); + } else { + NEXT_IMMEDIATE(ASYNC_CONNECT_END); + } + break; + case ASYNC_CONNECT_CONT: + connect_cont(event); + if (async_exit_status) { + next_event(ASYNC_CONNECT_CONT); + } else { + NEXT_IMMEDIATE(ASYNC_CONNECT_END); + } + break; + break; + case ASYNC_CONNECT_END: + if (!ret_mysql) { + fprintf(stderr,"Failed to mysql_real_connect()"); + NEXT_IMMEDIATE(ASYNC_CONNECT_FAILED); + } else { + NEXT_IMMEDIATE(ASYNC_CONNECT_SUCCESSFUL); + } + break; + case ASYNC_CONNECT_SUCCESSFUL: + break; + case ASYNC_CONNECT_FAILED: + break; + default: + assert(0); //we should never reach here + break; + } + return async_state_machine; +} + + +void MySQL_Connection::next_event(MDB_ASYNC_ST new_st) { + int fd; + wait_events=0; + + if (async_exit_status & MYSQL_WAIT_READ) + wait_events |= POLLIN; + if (async_exit_status & MYSQL_WAIT_WRITE) + wait_events|= POLLOUT; + if (wait_events) + fd= mysql_get_socket(mysql); + else + fd= -1; + if (async_exit_status & MYSQL_WAIT_TIMEOUT) { + timeout=10000; + //tv.tv_sec= 0; + //tv.tv_usec= 10000; + //ptv= &tv; + } else { + //ptv= NULL; + } + //event_set(ev_mysql, fd, wait_event, state_machine_handler, this); + //if (ev_mysql==NULL) { + // ev_mysql=event_new(base, fd, wait_event, state_machine_handler, this); + //event_add(ev_mysql, ptv); + //} + //event_del(ev_mysql); + //event_assign(ev_mysql, base, fd, wait_event, state_machine_handler, this); + //event_add(ev_mysql, ptv); + async_state_machine = new_st; +}; diff --git a/src/proxysql.cfg b/src/proxysql.cfg index 0c3e05a1a..0df9365b2 100644 --- a/src/proxysql.cfg +++ b/src/proxysql.cfg @@ -18,7 +18,7 @@ admin_variables= mysql_variables= { - threads=4 + threads=2 //threads=32 have_compress=true poll_timeout=2000