Related to bug #217, added command 'fail accept <errno>' to debug client's commands.
Reproduce #217 by connecting with telnet to debug client interface and execute command: fail accept 23 and try to execute read query, for example, with mysql -h 127.0.0.1 -P 4008 -u maxuser -pmaxpwd -e 'select current_user(), @@server_id'
This commit is contained in:
@ -216,6 +216,8 @@ memset(dcb_fake_write_errno, 0, sizeof(unsigned char)*1024);
|
|||||||
memset(dcb_fake_write_ev, 0, sizeof(__int32_t)*1024);
|
memset(dcb_fake_write_ev, 0, sizeof(__int32_t)*1024);
|
||||||
fail_next_backend_fd = false;
|
fail_next_backend_fd = false;
|
||||||
fail_next_client_fd = false;
|
fail_next_client_fd = false;
|
||||||
|
fail_next_accept = false;
|
||||||
|
fail_accept_errno = 0;
|
||||||
#endif
|
#endif
|
||||||
l = atexit(skygw_logmanager_exit);
|
l = atexit(skygw_logmanager_exit);
|
||||||
|
|
||||||
|
@ -190,6 +190,8 @@ unsigned char dcb_fake_write_errno[1024];
|
|||||||
__int32_t dcb_fake_write_ev[1024];
|
__int32_t dcb_fake_write_ev[1024];
|
||||||
bool fail_next_backend_fd;
|
bool fail_next_backend_fd;
|
||||||
bool fail_next_client_fd;
|
bool fail_next_client_fd;
|
||||||
|
bool fail_next_accept;
|
||||||
|
int fail_accept_errno;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* A few useful macros */
|
/* A few useful macros */
|
||||||
|
@ -127,7 +127,11 @@ mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mys
|
|||||||
|
|
||||||
affected_rows = in_affected_rows;
|
affected_rows = in_affected_rows;
|
||||||
|
|
||||||
mysql_payload_size = sizeof(field_count) + sizeof(affected_rows) + sizeof(insert_id) + sizeof(mysql_server_status) + sizeof(mysql_warning_count);
|
mysql_payload_size = sizeof(field_count) +
|
||||||
|
sizeof(affected_rows) +
|
||||||
|
sizeof(insert_id) +
|
||||||
|
sizeof(mysql_server_status) +
|
||||||
|
sizeof(mysql_warning_count);
|
||||||
|
|
||||||
if (mysql_message != NULL) {
|
if (mysql_message != NULL) {
|
||||||
mysql_payload_size += strlen(mysql_message);
|
mysql_payload_size += strlen(mysql_message);
|
||||||
@ -513,7 +517,6 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
CHK_DCB(dcb);
|
CHK_DCB(dcb);
|
||||||
|
|
||||||
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
|
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
|
||||||
CHK_PROTOCOL(protocol);
|
CHK_PROTOCOL(protocol);
|
||||||
/**
|
/**
|
||||||
@ -611,7 +614,6 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
* Read all the data that is available into a chain of buffers
|
* Read all the data that is available into a chain of buffers
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* int len; */
|
|
||||||
GWBUF *queue = NULL;
|
GWBUF *queue = NULL;
|
||||||
GWBUF *gw_buffer = NULL;
|
GWBUF *gw_buffer = NULL;
|
||||||
uint8_t *ptr_buff = NULL;
|
uint8_t *ptr_buff = NULL;
|
||||||
@ -639,34 +641,20 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
/* Now, we are assuming in the first buffer there is
|
/* Now, we are assuming in the first buffer there is
|
||||||
* the information form mysql command */
|
* the information form mysql command */
|
||||||
queue = gw_buffer;
|
queue = gw_buffer;
|
||||||
/* len = GWBUF_LENGTH(queue); */
|
|
||||||
ptr_buff = GWBUF_DATA(queue);
|
ptr_buff = GWBUF_DATA(queue);
|
||||||
|
|
||||||
/* get mysql commang at fifth byte */
|
/* get mysql commang at fifth byte */
|
||||||
if (ptr_buff) {
|
if (ptr_buff) {
|
||||||
mysql_command = ptr_buff[4];
|
mysql_command = ptr_buff[4];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mysql_command == '\x03') {
|
|
||||||
/**
|
/**
|
||||||
* SQL Trace here.
|
* Without rsession there is no access to backend.
|
||||||
* Length can be calculated and it must be passed as
|
* COM_QUIT : close client dcb
|
||||||
* argument.
|
* else : write custom error to client dcb.
|
||||||
*/
|
*/
|
||||||
/* this is a standard MySQL query !!!! */
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Routing Client input to Backend
|
|
||||||
*/
|
|
||||||
/* Do not route the query without session! */
|
|
||||||
if(rsession == NULL) {
|
if(rsession == NULL) {
|
||||||
|
/** COM_QUIT */
|
||||||
if (mysql_command == '\x01') {
|
if (mysql_command == '\x01') {
|
||||||
/**
|
|
||||||
* COM_QUIT handling
|
|
||||||
*
|
|
||||||
* fprintf(stderr, "COM_QUIT received with
|
|
||||||
* no connected backends from %i\n", dcb->fd);
|
|
||||||
*/
|
|
||||||
skygw_log_write_flush(
|
skygw_log_write_flush(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_client_event] Client read "
|
"%lu [gw_read_client_event] Client read "
|
||||||
@ -682,63 +670,52 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
dcb,
|
dcb,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
"Connection to backend lost");
|
"Query routing failed. Connection to "
|
||||||
|
"backend lost");
|
||||||
protocol->state = MYSQL_IDLE;
|
protocol->state = MYSQL_IDLE;
|
||||||
}
|
}
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
}
|
||||||
/* We can route the query */
|
/** Route COM_QUIT to backend */
|
||||||
/* COM_QUIT handling */
|
|
||||||
if (mysql_command == '\x01') {
|
if (mysql_command == '\x01') {
|
||||||
skygw_log_write_flush(
|
|
||||||
LOGFILE_DEBUG,
|
|
||||||
"%lu [gw_read_client_event] Before routeQuery. "
|
|
||||||
"dcb %p.",
|
|
||||||
pthread_self(),
|
|
||||||
dcb);
|
|
||||||
/**
|
|
||||||
* fprintf(stderr, "COM_QUIT received from %i and
|
|
||||||
* passed to backed\n", dcb->fd);
|
|
||||||
* this will propagate COM_QUIT to backend(s)
|
|
||||||
* fprintf(stderr, "<<< Routing the COM_QUIT ...\n");
|
|
||||||
*/
|
|
||||||
router->routeQuery(router_instance, rsession, queue);
|
router->routeQuery(router_instance, rsession, queue);
|
||||||
skygw_log_write_flush(
|
skygw_log_write_flush(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_client_event] After routeQuery. "
|
"%lu [gw_read_client_event] Routed COM_QUIT to "
|
||||||
"dcb %p.",
|
"backend. Close client dcb %p",
|
||||||
pthread_self(),
|
pthread_self(),
|
||||||
dcb);
|
dcb);
|
||||||
|
|
||||||
/* close client connection */
|
/** close client connection */
|
||||||
|
|
||||||
(dcb->func).close(dcb);
|
(dcb->func).close(dcb);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto return_rc;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* MySQL Command Routing */
|
{
|
||||||
|
/** Route other commands to backend */
|
||||||
protocol->state = MYSQL_ROUTING;
|
protocol->state = MYSQL_ROUTING;
|
||||||
|
|
||||||
/* writing in the backend buffer queue, via routeQuery */
|
|
||||||
//fprintf(stderr, "<<< Routing the Query ...\n");
|
|
||||||
rc = router->routeQuery(router_instance, rsession, queue);
|
rc = router->routeQuery(router_instance, rsession, queue);
|
||||||
|
/** succeed */
|
||||||
if (rc == 1) {
|
if (rc == 1) {
|
||||||
protocol->state = MYSQL_WAITING_RESULT;
|
protocol->state = MYSQL_WAITING_RESULT;
|
||||||
|
rc = 0; /**< here '0' means success */
|
||||||
} else {
|
} else {
|
||||||
mysql_send_custom_error(dcb,
|
mysql_send_custom_error(dcb,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
"Connection to backend lost.");
|
"Query routing failed. "
|
||||||
|
"Connection to backend "
|
||||||
|
"lost.");
|
||||||
protocol->state = MYSQL_IDLE;
|
protocol->state = MYSQL_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
} /* MYSQL_IDLE, MYSQL_WAITING_RESULT */
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// todo
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rc = 0;
|
rc = 0;
|
||||||
@ -950,6 +927,15 @@ int gw_MySQLAccept(DCB *listener)
|
|||||||
&addrlen);
|
&addrlen);
|
||||||
|
|
||||||
eno = errno;
|
eno = errno;
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
if (fail_next_accept) {
|
||||||
|
c_sock = -1;
|
||||||
|
eno = fail_accept_errno;
|
||||||
|
i = 10;
|
||||||
|
fail_next_accept = false;
|
||||||
|
fail_accept_errno = 0;
|
||||||
|
}
|
||||||
|
#endif /* SS_DEBUG */
|
||||||
|
|
||||||
if (c_sock == -1) {
|
if (c_sock == -1) {
|
||||||
|
|
||||||
@ -1105,9 +1091,9 @@ int gw_MySQLAccept(DCB *listener)
|
|||||||
CHK_PROTOCOL(protocol);
|
CHK_PROTOCOL(protocol);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return_rc:
|
return_rc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <service.h>
|
#include <service.h>
|
||||||
#include <session.h>
|
#include <session.h>
|
||||||
#include <router.h>
|
#include <router.h>
|
||||||
@ -189,10 +190,21 @@ static void disable_log_action(DCB *, char *);
|
|||||||
* * The subcommands of the enable command
|
* * The subcommands of the enable command
|
||||||
* */
|
* */
|
||||||
struct subcommand enableoptions[] = {
|
struct subcommand enableoptions[] = {
|
||||||
{ "log", 1, enable_log_action, "Enable Log options for MaxScale, options trace | error | message E.g. enable log message.",
|
{
|
||||||
{ARG_TYPE_STRING, 0, 0} },
|
"log",
|
||||||
{ NULL, 0, NULL, NULL,
|
1,
|
||||||
{0, 0, 0} }
|
enable_log_action,
|
||||||
|
"Enable Log options for MaxScale, options trace | error | "
|
||||||
|
"message E.g. enable log message.",
|
||||||
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
{0, 0, 0}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -200,17 +212,28 @@ struct subcommand enableoptions[] = {
|
|||||||
* * The subcommands of the disable command
|
* * The subcommands of the disable command
|
||||||
* */
|
* */
|
||||||
struct subcommand disableoptions[] = {
|
struct subcommand disableoptions[] = {
|
||||||
{ "log", 1, disable_log_action, "Disable Log for MaxScale, Options: trace | error | message E.g. disable log trace",
|
{
|
||||||
{ARG_TYPE_STRING, 0, 0} },
|
"log",
|
||||||
{ NULL, 0, NULL, NULL,
|
1,
|
||||||
{0, 0, 0} }
|
disable_log_action,
|
||||||
|
"Disable Log for MaxScale, Options: trace | error | message E.g. "
|
||||||
|
"disable log trace",
|
||||||
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
{0, 0, 0}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
|
|
||||||
static void fail_backendfd(void);
|
static void fail_backendfd(void);
|
||||||
static void fail_clientfd(void);
|
static void fail_clientfd(void);
|
||||||
|
static void fail_accept(DCB* dcb, char* arg1);
|
||||||
/**
|
/**
|
||||||
* * The subcommands of the fail command
|
* * The subcommands of the fail command
|
||||||
* */
|
* */
|
||||||
@ -229,6 +252,13 @@ struct subcommand failoptions[] = {
|
|||||||
"Fail client socket for next operation.",
|
"Fail client socket for next operation.",
|
||||||
{ARG_TYPE_STRING, 0, 0}
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"accept",
|
||||||
|
1,
|
||||||
|
fail_accept,
|
||||||
|
"Fail to accept next client connection.",
|
||||||
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
@ -735,11 +765,42 @@ static void disable_log_action(DCB *dcb, char *arg1) {
|
|||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
static void fail_backendfd(void)
|
static void fail_backendfd(void)
|
||||||
{
|
{
|
||||||
fail_next_backend_fd = TRUE;
|
fail_next_backend_fd = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fail_clientfd(void)
|
static void fail_clientfd(void)
|
||||||
{
|
{
|
||||||
fail_next_client_fd = TRUE;
|
fail_next_client_fd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fail_accept(
|
||||||
|
DCB* dcb,
|
||||||
|
char* arg1)
|
||||||
|
{
|
||||||
|
fail_accept_errno = atoi(arg1);
|
||||||
|
|
||||||
|
switch(fail_accept_errno) {
|
||||||
|
case EAGAIN:
|
||||||
|
// case EWOULDBLOCK:
|
||||||
|
case EBADF:
|
||||||
|
case EINTR:
|
||||||
|
case EINVAL:
|
||||||
|
case EMFILE:
|
||||||
|
case ENFILE:
|
||||||
|
case ENOTSOCK:
|
||||||
|
case EOPNOTSUPP:
|
||||||
|
case ENOBUFS:
|
||||||
|
case ENOMEM:
|
||||||
|
case EPROTO:
|
||||||
|
fail_next_accept = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dcb_printf(dcb,
|
||||||
|
"[%d, %s] is not valid errno for accept.\n",
|
||||||
|
fail_accept_errno,
|
||||||
|
strerror(fail_accept_errno));
|
||||||
|
return ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user