From 48158560170592edfdd65f16fec93d2886fdfe50 Mon Sep 17 00:00:00 2001 From: vraatikka Date: Fri, 13 Sep 2013 23:55:26 +0300 Subject: [PATCH] session.c : session_alloc If backend connection can't be created, backend_dcb is not create, router client session is not created and what already is created in session_alloc, is freed. mysql_client.c : gw_read_client_event If session creation failed, then - instead of sending ok to client, "failed to create new session" is sent and client dcb is closed. : gw_MySQLAccept removed loop where accept was called again and again. With single thread looping forever is not possible because there's no one to free previously allocated resources. If accept fails ten times in a row, then return without new client dcb. --- server/core/dcb.c | 15 +++++++- server/core/session.c | 18 ++++++++- server/modules/protocol/mysql_client.c | 52 ++++++++++++++++++-------- server/modules/protocol/mysql_common.c | 18 ++++++++- 4 files changed, 82 insertions(+), 21 deletions(-) diff --git a/server/core/dcb.c b/server/core/dcb.c index 0198aa13b..49342299c 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -422,7 +422,7 @@ bool succp = false; dcb->fd, dcb); conn_open[dcb->fd] = false; - ss_debug(dcb->fd = 0;) + ss_debug(dcb->fd = -1;) } #endif succp = dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL); @@ -494,7 +494,18 @@ int fd; dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL); dcb_final_free(dcb); return NULL; - } + } else { + skygw_log_write_flush( + LOGFILE_TRACE, + "%lu [dcb_connect] Connected to server %s:%d, " + "from backend dcb %p, client dcp %p fd %d\n", + pthread_self(), + server->name, + server->port, + dcb, + session->client, + session->client->fd); + } ss_dassert(dcb->fd = -1); /** * Successfully connected to backend. Assign file descriptor to dcb diff --git a/server/core/session.c b/server/core/session.c index 04021475c..d76ad6855 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -75,7 +75,7 @@ session_alloc(SERVICE *service, DCB *client) pthread_self(), eno, strerror(eno)); - return NULL; + goto return_session; } #if defined(SS_DEBUG) session->ses_chk_top = CHK_NUM_SESSION; @@ -121,7 +121,19 @@ session_alloc(SERVICE *service, DCB *client) { session->router_session = service->router->newSession(service->router_instance, session); - } + + if (session->router_session == NULL) { + client->session = NULL; + skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [session_alloc] Creating router client session " + "failed. Freeing session.", + pthread_self()); + free(session); + session = NULL; + goto return_session; + } + } spinlock_acquire(&session_spin); session->next = allSessions; allSessions = session; @@ -129,6 +141,8 @@ session_alloc(SERVICE *service, DCB *client) atomic_add(&service->stats.n_sessions, 1); atomic_add(&service->stats.n_current, 1); CHK_SESSION(session); + +return_session: return session; } diff --git a/server/modules/protocol/mysql_client.c b/server/modules/protocol/mysql_client.c index 11692b060..1f12924ff 100644 --- a/server/modules/protocol/mysql_client.c +++ b/server/modules/protocol/mysql_client.c @@ -576,10 +576,21 @@ int gw_read_client_event(DCB* dcb) { //write to client mysql AUTH_OK packet, packet n. is 2 // start a new session, and connect to backends session = session_alloc(dcb->service, dcb); - CHK_SESSION(session); - ss_dassert(session->state != SESSION_STATE_ALLOC); - protocol->state = MYSQL_IDLE; - mysql_send_ok(dcb, 2, 0, NULL); + + if (session != NULL) { + CHK_SESSION(session); + ss_dassert(session->state != SESSION_STATE_ALLOC); + protocol->state = MYSQL_IDLE; + mysql_send_ok(dcb, 2, 0, NULL); + } else { + protocol->state = MYSQL_AUTH_FAILED; + mysql_send_auth_error( + dcb, + 2, + 0, + "failed to create new session"); + dcb->func.close(dcb); + } } else { @@ -877,8 +888,13 @@ int gw_MySQLAccept(DCB *listener) pthread_self(), eno, strerror(eno)); - usleep(100*i*i++); - goto retry_accept; + i++; + usleep(100*i*i); + + if (i<10) { + goto retry_accept; + } + goto return_to_poll; } else if (eno == EMFILE) { @@ -891,8 +907,13 @@ int gw_MySQLAccept(DCB *listener) pthread_self(), eno, strerror(eno)); - usleep(100*i*i++); - goto retry_accept; + i++; + usleep(100*i*i); + + if (i<10) { + goto retry_accept; + } + goto return_to_poll; } else { @@ -914,14 +935,12 @@ int gw_MySQLAccept(DCB *listener) listener->stats.n_accepts++; #if defined(SS_DEBUG) - if (c_sock > 0) { - skygw_log_write_flush( - LOGFILE_TRACE, - "%lu [gw_MySQLAccept] Accepted fd %d.", - pthread_self(), - c_sock); - conn_open[c_sock] = true; - } + skygw_log_write_flush( + LOGFILE_TRACE, + "%lu [gw_MySQLAccept] Accepted fd %d.", + pthread_self(), + c_sock); + conn_open[c_sock] = true; #endif fprintf(stderr, "Processing %i connection fd %i for listener %i\n", @@ -986,6 +1005,7 @@ int gw_MySQLAccept(DCB *listener) client_dcb->fd); } } /**< while 1 */ +return_to_poll: return 0; } diff --git a/server/modules/protocol/mysql_common.c b/server/modules/protocol/mysql_common.c index 332103d61..dcf3c45ae 100644 --- a/server/modules/protocol/mysql_common.c +++ b/server/modules/protocol/mysql_common.c @@ -569,6 +569,9 @@ int gw_do_connect_to_backend( if (eno == EINPROGRESS) { rv = 1; } else { + int rc; + int oldfd = so; + skygw_log_write_flush( LOGFILE_ERROR, "%lu [gw_do_connect_to_backend] Failed to " @@ -580,7 +583,20 @@ int gw_do_connect_to_backend( eno, strerror(eno)); /** Close newly created socket. */ - close(so); + rc = close(so); + + if (rc != 0) { + int eno = errno; + errno = 0; + skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [gw_do_connect_to_backend] Failed to " + "close socket %d due %d, %s.", + pthread_self(), + oldfd, + eno, + strerror(eno)); + } goto return_rv; } }