static int async1(MYSQL *my) { int err; MYSQL mysql, *ret; MYSQL_RES *res; MYSQL_ROW row; int status; uint default_timeout; int i; for (i=0; i < 100; i++) { mysql_init(&mysql); mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0); /* set timeouts to 300 microseconds */ default_timeout= 300; mysql_options(&mysql, MYSQL_OPT_READ_TIMEOUT, &default_timeout); mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, &default_timeout); mysql_options(&mysql, MYSQL_OPT_WRITE_TIMEOUT, &default_timeout); mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp"); /* Returns 0 when done, else flag for what to wait for when need to block. */ status= mysql_real_connect_start(&ret, &mysql, hostname, username, password, NULL, 0, NULL, 0); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_real_connect_cont(&ret, &mysql, status); } FAIL_IF(!ret, "Failed to mysql_real_connect()"); status= mysql_real_query_start(&err, &mysql, SL("SHOW STATUS")); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_real_query_cont(&err, &mysql, status); } FAIL_IF(err, "mysql_real_query() returns error"); /* This method cannot block. */ res= mysql_use_result(&mysql); FAIL_IF(!res, "mysql_use_result() returns error"); for (;;) { status= mysql_fetch_row_start(&row, res); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_fetch_row_cont(&row, res, status); } if (!row) break; } FAIL_IF(mysql_errno(&mysql), "Got error while retrieving rows"); mysql_free_result(res); /* mysql_close() sends a COM_QUIT packet, and so in principle could block waiting for the socket to accept the data. In practise, for many applications it will probably be fine to use the blocking mysql_close(). */ status= mysql_close_start(&mysql); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_close_cont(&mysql, status); } } return OK; }
static void doit(const char *host, const char *user, const char *password) { int err; MYSQL mysql, *ret; MYSQL_RES *res; MYSQL_ROW row; int status; mysql_init(&mysql); mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0); mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp"); /* Returns 0 when done, else flag for what to wait for when need to block. */ status= mysql_real_connect_start(&ret, &mysql, host, user, password, NULL, 0, NULL, 0); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_real_connect_cont(&ret, &mysql, status); } if (!ret) fatal(&mysql, "Failed to mysql_real_connect()"); status= mysql_real_query_start(&err, &mysql, SL("SHOW STATUS")); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_real_query_cont(&err, &mysql, status); } if (err) fatal(&mysql, "mysql_real_query() returns error"); /* This method cannot block. */ res= mysql_use_result(&mysql); if (!res) fatal(&mysql, "mysql_use_result() returns error"); for (;;) { status= mysql_fetch_row_start(&row, res); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_fetch_row_cont(&row, res, status); } if (!row) break; printf("%s: %s\n", row[0], row[1]); } if (mysql_errno(&mysql)) fatal(&mysql, "Got error while retrieving rows"); mysql_free_result(res); /* mysql_close() sends a COM_QUIT packet, and so in principle could block waiting for the socket to accept the data. In practise, for many applications it will probably be fine to use the blocking mysql_close(). */ status= mysql_close_start(&mysql); while (status) { status= wait_for_mysql(&mysql, status); status= mysql_close_cont(&mysql, status); } }
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; myds->wait_until=myds->sess->thread->curtime+mysql_thread___connect_timeout_server*1000; } handler_again: proxy_debug(PROXY_DEBUG_MYSQL_PROTOCOL, 6,"async_state_machine=%d\n", async_state_machine); 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: if (event) { connect_cont(event); } if (async_exit_status) { if (myds->sess->thread->curtime >= myds->wait_until) { NEXT_IMMEDIATE(ASYNC_CONNECT_TIMEOUT); } next_event(ASYNC_CONNECT_CONT); } else { NEXT_IMMEDIATE(ASYNC_CONNECT_END); } break; break; case ASYNC_CONNECT_END: if (!ret_mysql) { // always increase the counter proxy_error("Failed to mysql_real_connect() on %s:%d , %d: %s\n", parent->address, parent->port, mysql_errno(mysql), mysql_error(mysql)); NEXT_IMMEDIATE(ASYNC_CONNECT_FAILED); } else { NEXT_IMMEDIATE(ASYNC_CONNECT_SUCCESSFUL); } break; case ASYNC_CONNECT_SUCCESSFUL: __sync_fetch_and_add(&MyHGM->status.server_connections_connected,1); __sync_fetch_and_add(&parent->connect_OK,1); break; case ASYNC_CONNECT_FAILED: parent->connect_error(mysql_errno(mysql)); break; case ASYNC_CONNECT_TIMEOUT: proxy_error("Connect timeout on %s:%d : %llu - %llu = %llu\n", parent->address, parent->port, myds->sess->thread->curtime , myds->wait_until, myds->sess->thread->curtime - myds->wait_until); parent->connect_error(mysql_errno(mysql)); break; case ASYNC_CHANGE_USER_START: change_user_start(); if (async_exit_status) { next_event(ASYNC_CHANGE_USER_CONT); } else { NEXT_IMMEDIATE(ASYNC_CHANGE_USER_END); } break; case ASYNC_CHANGE_USER_CONT: assert(myds->sess->status==CHANGING_USER_SERVER); change_user_cont(event); if (async_exit_status) { next_event(ASYNC_CHANGE_USER_CONT); } else { NEXT_IMMEDIATE(ASYNC_CHANGE_USER_END); } break; case ASYNC_CHANGE_USER_END: if (ret_bool) { fprintf(stderr,"Failed to mysql_change_user()"); NEXT_IMMEDIATE(ASYNC_CHANGE_USER_FAILED); } else { NEXT_IMMEDIATE(ASYNC_CHANGE_USER_SUCCESSFUL); } break; case ASYNC_CHANGE_USER_SUCCESSFUL: break; case ASYNC_CHANGE_USER_FAILED: break; case ASYNC_PING_START: ping_start(); if (async_exit_status) { next_event(ASYNC_PING_CONT); } else { NEXT_IMMEDIATE(ASYNC_PING_END); } break; case ASYNC_PING_CONT: assert(myds->sess->status==PINGING_SERVER); ping_cont(event); if (async_exit_status) { next_event(ASYNC_PING_CONT); } else { NEXT_IMMEDIATE(ASYNC_PING_END); } break; case ASYNC_PING_END: if (interr) { NEXT_IMMEDIATE(ASYNC_PING_FAILED); } else { NEXT_IMMEDIATE(ASYNC_PING_SUCCESSFUL); } break; case ASYNC_PING_SUCCESSFUL: break; case ASYNC_PING_FAILED: break; case ASYNC_QUERY_START: real_query_start(); __sync_fetch_and_add(&parent->queries_sent,1); __sync_fetch_and_add(&parent->bytes_sent,query.length); myds->sess->thread->status_variables.queries_backends_bytes_sent+=query.length; if (async_exit_status) { next_event(ASYNC_QUERY_CONT); } else { #ifdef PROXYSQL_USE_RESULT NEXT_IMMEDIATE(ASYNC_USE_RESULT_START); #else NEXT_IMMEDIATE(ASYNC_STORE_RESULT_START); #endif } break; case ASYNC_QUERY_CONT: real_query_cont(event); if (async_exit_status) { next_event(ASYNC_QUERY_CONT); } else { #ifdef PROXYSQL_USE_RESULT NEXT_IMMEDIATE(ASYNC_USE_RESULT_START); #else NEXT_IMMEDIATE(ASYNC_STORE_RESULT_START); #endif } break; case ASYNC_STORE_RESULT_START: if (mysql_errno(mysql)) { NEXT_IMMEDIATE(ASYNC_QUERY_END); } store_result_start(); if (async_exit_status) { next_event(ASYNC_STORE_RESULT_CONT); } else { NEXT_IMMEDIATE(ASYNC_QUERY_END); } break; case ASYNC_STORE_RESULT_CONT: store_result_cont(event); if (async_exit_status) { next_event(ASYNC_STORE_RESULT_CONT); } else { NEXT_IMMEDIATE(ASYNC_QUERY_END); } break; case ASYNC_USE_RESULT_START: if (mysql_errno(mysql)) { NEXT_IMMEDIATE(ASYNC_QUERY_END); } mysql_result=mysql_use_result(mysql); if (mysql_result==NULL) { NEXT_IMMEDIATE(ASYNC_QUERY_END); } else { MyRS=new MySQL_ResultSet(&myds->sess->client_myds->myprot, mysql_result, mysql); async_fetch_row_start=false; NEXT_IMMEDIATE(ASYNC_USE_RESULT_CONT); } break; case ASYNC_USE_RESULT_CONT: if (async_fetch_row_start==false) { async_exit_status=mysql_fetch_row_start(&mysql_row,mysql_result); async_fetch_row_start=true; } else { async_exit_status=mysql_fetch_row_cont(&mysql_row,mysql_result, mysql_status(event, true)); } if (async_exit_status) { next_event(ASYNC_USE_RESULT_CONT); } else { async_fetch_row_start=false; if (mysql_row) { unsigned int br=MyRS->add_row(mysql_row); __sync_fetch_and_add(&parent->bytes_recv,br); myds->sess->thread->status_variables.queries_backends_bytes_recv+=br; NEXT_IMMEDIATE(ASYNC_USE_RESULT_CONT); } else { MyRS->add_eof(); NEXT_IMMEDIATE(ASYNC_QUERY_END); } } break; case ASYNC_QUERY_END: break; case ASYNC_SET_AUTOCOMMIT_START: set_autocommit_start(); if (async_exit_status) { next_event(ASYNC_SET_AUTOCOMMIT_CONT); } else { NEXT_IMMEDIATE(ASYNC_SET_AUTOCOMMIT_END); } break; case ASYNC_SET_AUTOCOMMIT_CONT: set_autocommit_cont(event); if (async_exit_status) { next_event(ASYNC_SET_AUTOCOMMIT_CONT); } else { NEXT_IMMEDIATE(ASYNC_SET_AUTOCOMMIT_END); } break; case ASYNC_SET_AUTOCOMMIT_END: if (ret_bool) { NEXT_IMMEDIATE(ASYNC_SET_AUTOCOMMIT_FAILED); } else { NEXT_IMMEDIATE(ASYNC_SET_AUTOCOMMIT_SUCCESSFUL); } break; case ASYNC_SET_AUTOCOMMIT_SUCCESSFUL: break; case ASYNC_SET_AUTOCOMMIT_FAILED: fprintf(stderr,"%s\n",mysql_error(mysql)); break; case ASYNC_SET_NAMES_START: set_names_start(); if (async_exit_status) { next_event(ASYNC_SET_NAMES_CONT); } else { NEXT_IMMEDIATE(ASYNC_SET_NAMES_END); } break; case ASYNC_SET_NAMES_CONT: set_names_cont(event); if (async_exit_status) { next_event(ASYNC_SET_NAMES_CONT); } else { NEXT_IMMEDIATE(ASYNC_SET_NAMES_END); } break; case ASYNC_SET_NAMES_END: if (interr) { NEXT_IMMEDIATE(ASYNC_SET_NAMES_FAILED); } else { NEXT_IMMEDIATE(ASYNC_SET_NAMES_SUCCESSFUL); } break; case ASYNC_SET_NAMES_SUCCESSFUL: break; case ASYNC_SET_NAMES_FAILED: fprintf(stderr,"%s\n",mysql_error(mysql)); break; case ASYNC_INITDB_START: initdb_start(); if (async_exit_status) { next_event(ASYNC_INITDB_CONT); } else { NEXT_IMMEDIATE(ASYNC_INITDB_END); } break; case ASYNC_INITDB_CONT: initdb_cont(event); if (async_exit_status) { next_event(ASYNC_INITDB_CONT); } else { NEXT_IMMEDIATE(ASYNC_INITDB_END); } break; case ASYNC_INITDB_END: if (interr) { NEXT_IMMEDIATE(ASYNC_INITDB_FAILED); } else { NEXT_IMMEDIATE(ASYNC_INITDB_SUCCESSFUL); } break; case ASYNC_INITDB_SUCCESSFUL: break; case ASYNC_INITDB_FAILED: fprintf(stderr,"%s\n",mysql_error(mysql)); break; default: assert(0); //we should never reach here break; } return async_state_machine; }
static void state_machine_handler(int fd __attribute__((unused)), short event, void *arg) { struct state_data *sd= arg; int status; again: switch(sd->ST) { case 0: /* Initial state, start making the connection. */ status= mysql_real_connect_start(&sd->ret, &sd->mysql, opt_host, opt_user, opt_password, opt_db, opt_port, opt_socket, 0); if (status) /* Wait for connect to complete. */ next_event(1, status, sd); else NEXT_IMMEDIATE(sd, 9); break; case 1: status= mysql_real_connect_cont(&sd->ret, &sd->mysql, mysql_status(event)); if (status) next_event(1, status, sd); else NEXT_IMMEDIATE(sd, 9); break; case 9: if (!sd->ret) fatal(sd, "Failed to mysql_real_connect()"); NEXT_IMMEDIATE(sd, 10); break; case 10: /* Now run the next query. */ sd->query_element= query_list; if (!sd->query_element) { /* No more queries, end the connection. */ NEXT_IMMEDIATE(sd, 40); } query_list= query_list->next; sd->index= sd->query_element->index; printf("%d ! %s\n", sd->index, sd->query_element->query); status= mysql_real_query_start(&sd->err, &sd->mysql, sd->query_element->query, strlen(sd->query_element->query)); if (status) next_event(11, status, sd); else NEXT_IMMEDIATE(sd, 20); break; case 11: status= mysql_real_query_cont(&sd->err, &sd->mysql, mysql_status(event)); if (status) next_event(11, status, sd); else NEXT_IMMEDIATE(sd, 20); break; case 20: my_free(sd->query_element->query); my_free(sd->query_element); if (sd->err) { printf("%d | Error: %s\n", sd->index, mysql_error(&sd->mysql)); NEXT_IMMEDIATE(sd, 10); } else { sd->result= mysql_use_result(&sd->mysql); if (!sd->result) fatal(sd, "mysql_use_result() returns error"); NEXT_IMMEDIATE(sd, 30); } break; case 30: status= mysql_fetch_row_start(&sd->row, sd->result); if (status) next_event(31, status, sd); else NEXT_IMMEDIATE(sd, 39); break; case 31: status= mysql_fetch_row_cont(&sd->row, sd->result, mysql_status(event)); if (status) next_event(31, status, sd); else NEXT_IMMEDIATE(sd, 39); break; case 39: if (sd->row) { /* Got a row. */ unsigned int i; printf("%d - ", sd->index); for (i= 0; i < mysql_num_fields(sd->result); i++) printf("%s%s", (i ? "\t" : ""), (sd->row[i] ? sd->row[i] : "(null)")); printf ("\n"); NEXT_IMMEDIATE(sd, 30); } else { if (mysql_errno(&sd->mysql)) { /* An error occured. */ printf("%d | Error: %s\n", sd->index, mysql_error(&sd->mysql)); } else { /* EOF. */ printf("%d | EOF\n", sd->index); } mysql_free_result(sd->result); NEXT_IMMEDIATE(sd, 10); } break; case 40: status= mysql_close_start(&sd->mysql); if (status) next_event(41, status, sd); else NEXT_IMMEDIATE(sd, 50); break; case 41: status= mysql_close_cont(&sd->mysql, mysql_status(event)); if (status) next_event(41, status, sd); else NEXT_IMMEDIATE(sd, 50); break; case 50: /* We are done! */ num_active_connections--; if (num_active_connections == 0) event_loopbreak(); break; default: abort(); } }