Merge branch 'develop' into MAX-111
This commit is contained in:
@ -39,9 +39,11 @@ ln -s /lib64/libaio.so.1 /lib64/libaio.so
|
|||||||
|
|
||||||
%install
|
%install
|
||||||
mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d/
|
mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d/
|
||||||
|
mkdir -p $RPM_BUILD_ROOT/etc/init.d/
|
||||||
mkdir -p $RPM_BUILD_ROOT%{install_path}
|
mkdir -p $RPM_BUILD_ROOT%{install_path}
|
||||||
cp -r binaries/* $RPM_BUILD_ROOT%{install_path}
|
cp -r binaries/* $RPM_BUILD_ROOT%{install_path}
|
||||||
cp maxscale.conf $RPM_BUILD_ROOT/etc/ld.so.conf.d/
|
cp maxscale.conf $RPM_BUILD_ROOT/etc/ld.so.conf.d/
|
||||||
|
cp -r etc/init.d/maxscale $RPM_BUILD_ROOT/etc/init.d/
|
||||||
|
|
||||||
%clean
|
%clean
|
||||||
|
|
||||||
@ -49,5 +51,6 @@ cp maxscale.conf $RPM_BUILD_ROOT/etc/ld.so.conf.d/
|
|||||||
%defattr(-,root,root)
|
%defattr(-,root,root)
|
||||||
%{install_path}
|
%{install_path}
|
||||||
/etc/ld.so.conf.d/maxscale.conf
|
/etc/ld.so.conf.d/maxscale.conf
|
||||||
|
/etc/inid.d/maxscale
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
@ -101,7 +101,8 @@ static int is_autocommit_stmt(
|
|||||||
*/
|
*/
|
||||||
skygw_query_type_t skygw_query_classifier_get_type(
|
skygw_query_type_t skygw_query_classifier_get_type(
|
||||||
const char* query,
|
const char* query,
|
||||||
unsigned long client_flags)
|
unsigned long client_flags,
|
||||||
|
MYSQL** p_mysql)
|
||||||
{
|
{
|
||||||
MYSQL* mysql;
|
MYSQL* mysql;
|
||||||
char* query_str;
|
char* query_str;
|
||||||
@ -129,9 +130,13 @@ skygw_query_type_t skygw_query_classifier_get_type(
|
|||||||
mysql_error(mysql))));
|
mysql_error(mysql))));
|
||||||
|
|
||||||
mysql_library_end();
|
mysql_library_end();
|
||||||
goto return_without_server;
|
goto return_qtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_mysql != NULL)
|
||||||
|
{
|
||||||
|
*p_mysql = mysql;
|
||||||
|
}
|
||||||
/** Set methods and authentication to mysql */
|
/** Set methods and authentication to mysql */
|
||||||
mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "libmysqld_skygw");
|
mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "libmysqld_skygw");
|
||||||
mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
|
mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
|
||||||
@ -143,25 +148,39 @@ skygw_query_type_t skygw_query_classifier_get_type(
|
|||||||
/** Get one or create new THD object to be use in parsing */
|
/** Get one or create new THD object to be use in parsing */
|
||||||
thd = get_or_create_thd_for_parsing(mysql, query_str);
|
thd = get_or_create_thd_for_parsing(mysql, query_str);
|
||||||
|
|
||||||
if (thd == NULL) {
|
if (thd == NULL)
|
||||||
goto return_with_server_handle;
|
{
|
||||||
|
skygw_query_classifier_free(mysql);
|
||||||
}
|
}
|
||||||
/** Create parse_tree inside thd */
|
/** Create parse_tree inside thd */
|
||||||
failp = create_parse_tree(thd);
|
failp = create_parse_tree(thd);
|
||||||
|
|
||||||
if (failp) {
|
if (failp)
|
||||||
goto return_with_thd;
|
{
|
||||||
|
skygw_query_classifier_free(mysql);
|
||||||
|
*p_mysql = NULL;
|
||||||
}
|
}
|
||||||
qtype = resolve_query_type(thd);
|
qtype = resolve_query_type(thd);
|
||||||
|
|
||||||
return_with_thd:
|
if (p_mysql == NULL)
|
||||||
|
{
|
||||||
|
skygw_query_classifier_free(mysql);
|
||||||
|
}
|
||||||
|
return_qtype:
|
||||||
|
return qtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void skygw_query_classifier_free(
|
||||||
|
MYSQL* mysql)
|
||||||
|
{
|
||||||
|
if (mysql->thd != NULL)
|
||||||
|
{
|
||||||
(*mysql->methods->free_embedded_thd)(mysql);
|
(*mysql->methods->free_embedded_thd)(mysql);
|
||||||
mysql->thd = 0;
|
mysql->thd = NULL;
|
||||||
return_with_server_handle:
|
}
|
||||||
mysql_close(mysql);
|
mysql_close(mysql);
|
||||||
mysql_thread_end();
|
mysql_thread_end();
|
||||||
return_without_server:
|
|
||||||
return qtype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -492,6 +511,7 @@ static skygw_query_type_t resolve_query_type(
|
|||||||
}
|
}
|
||||||
/**<! fall through */
|
/**<! fall through */
|
||||||
case SQLCOM_CHANGE_DB:
|
case SQLCOM_CHANGE_DB:
|
||||||
|
case SQLCOM_DEALLOCATE_PREPARE:
|
||||||
type |= QUERY_TYPE_SESSION_WRITE;
|
type |= QUERY_TYPE_SESSION_WRITE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -518,6 +538,11 @@ static skygw_query_type_t resolve_query_type(
|
|||||||
goto return_qtype;
|
goto return_qtype;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_PREPARE:
|
||||||
|
type |= QUERY_TYPE_PREPARE_NAMED_STMT;
|
||||||
|
goto return_qtype;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -783,3 +808,11 @@ static int is_autocommit_stmt(
|
|||||||
return_rc:
|
return_rc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* skygw_query_classifier_get_stmtname(
|
||||||
|
MYSQL* mysql)
|
||||||
|
{
|
||||||
|
return ((THD *)(mysql->thd))->lex->prepared_stmt_name.str;
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ Copyright SkySQL Ab
|
|||||||
|
|
||||||
/** getpid */
|
/** getpid */
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <mysql.h>
|
||||||
#include "../utils/skygw_utils.h"
|
#include "../utils/skygw_utils.h"
|
||||||
|
|
||||||
EXTERN_C_BLOCK_BEGIN
|
EXTERN_C_BLOCK_BEGIN
|
||||||
@ -29,25 +30,36 @@ EXTERN_C_BLOCK_BEGIN
|
|||||||
* is modified
|
* is modified
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUERY_TYPE_UNKNOWN = 0x000, /*< Initial value, can't be tested bitwisely */
|
QUERY_TYPE_UNKNOWN = 0x0000, /*< Initial value, can't be tested bitwisely */
|
||||||
QUERY_TYPE_LOCAL_READ = 0x001, /*< Read non-database data, execute in MaxScale */
|
QUERY_TYPE_LOCAL_READ = 0x0001, /*< Read non-database data, execute in MaxScale */
|
||||||
QUERY_TYPE_READ = 0x002, /*< No updates */
|
QUERY_TYPE_READ = 0x0002, /*< No updates */
|
||||||
QUERY_TYPE_WRITE = 0x004, /*< Master data will be modified */
|
QUERY_TYPE_WRITE = 0x0004, /*< Master data will be modified */
|
||||||
QUERY_TYPE_SESSION_WRITE = 0x008, /*< Session data will be modified */
|
QUERY_TYPE_SESSION_WRITE = 0x0008, /*< Session data will be modified */
|
||||||
QUERY_TYPE_GLOBAL_WRITE = 0x010, /*< Global system variable modification */
|
QUERY_TYPE_GLOBAL_WRITE = 0x0010, /*< Global system variable modification */
|
||||||
QUERY_TYPE_BEGIN_TRX = 0x020, /*< BEGIN or START TRANSACTION */
|
QUERY_TYPE_BEGIN_TRX = 0x0020, /*< BEGIN or START TRANSACTION */
|
||||||
QUERY_TYPE_ENABLE_AUTOCOMMIT = 0x040,/*< SET autocommit=1 */
|
QUERY_TYPE_ENABLE_AUTOCOMMIT = 0x0040, /*< SET autocommit=1 */
|
||||||
QUERY_TYPE_DISABLE_AUTOCOMMIT = 0x080,/*< SET autocommit=0 */
|
QUERY_TYPE_DISABLE_AUTOCOMMIT = 0x0080, /*< SET autocommit=0 */
|
||||||
QUERY_TYPE_ROLLBACK = 0x100, /*< ROLLBACK */
|
QUERY_TYPE_ROLLBACK = 0x0100, /*< ROLLBACK */
|
||||||
QUERY_TYPE_COMMIT = 0x200 /*< COMMIT */
|
QUERY_TYPE_COMMIT = 0x0200, /*< COMMIT */
|
||||||
|
QUERY_TYPE_PREPARE_NAMED_STMT = 0x0400, /*< Prepared stmt with name from user */
|
||||||
|
QUERY_TYPE_PREPARE_STMT = 0x0800, /*< Prepared stmt with id provided by server */
|
||||||
|
QUERY_TYPE_EXEC_STMT = 0x1000 /*< Execute prepared statement */
|
||||||
} skygw_query_type_t;
|
} skygw_query_type_t;
|
||||||
|
|
||||||
#define QUERY_IS_TYPE(mask,type) ((mask & type) == type)
|
#define QUERY_IS_TYPE(mask,type) ((mask & type) == type)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create THD and use it for creating parse tree. Examine parse tree and
|
||||||
|
* classify the query.
|
||||||
|
*/
|
||||||
skygw_query_type_t skygw_query_classifier_get_type(
|
skygw_query_type_t skygw_query_classifier_get_type(
|
||||||
const char* query_str,
|
const char* query_str,
|
||||||
unsigned long client_flags);
|
unsigned long client_flags,
|
||||||
|
MYSQL** mysql);
|
||||||
|
|
||||||
|
/** Free THD context and close MYSQL */
|
||||||
|
void skygw_query_classifier_free(MYSQL* mysql);
|
||||||
|
char* skygw_query_classifier_get_stmtname(MYSQL* mysql);
|
||||||
|
|
||||||
EXTERN_C_BLOCK_END
|
EXTERN_C_BLOCK_END
|
||||||
|
|
||||||
|
@ -186,10 +186,9 @@ GWBUF *gwbuf_clone_transform(
|
|||||||
goto return_clonebuf;
|
goto return_clonebuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (src_type)
|
if (GWBUF_IS_TYPE_MYSQL(head))
|
||||||
{
|
{
|
||||||
case GWBUF_TYPE_MYSQL:
|
if (GWBUF_TYPE_PLAINSQL == targettype)
|
||||||
if (targettype == GWBUF_TYPE_PLAINSQL)
|
|
||||||
{
|
{
|
||||||
/** Crete reference to string part of buffer */
|
/** Crete reference to string part of buffer */
|
||||||
clonebuf = gwbuf_clone_portion(
|
clonebuf = gwbuf_clone_portion(
|
||||||
@ -198,18 +197,17 @@ GWBUF *gwbuf_clone_transform(
|
|||||||
GWBUF_LENGTH(head)-5);
|
GWBUF_LENGTH(head)-5);
|
||||||
ss_dassert(clonebuf != NULL);
|
ss_dassert(clonebuf != NULL);
|
||||||
/** Overwrite the type with new format */
|
/** Overwrite the type with new format */
|
||||||
clonebuf->gwbuf_type = targettype;
|
gwbuf_set_type(clonebuf, targettype);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
clonebuf = NULL;
|
clonebuf = NULL;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
else
|
||||||
default:
|
{
|
||||||
clonebuf = NULL;
|
clonebuf = NULL;
|
||||||
break;
|
}
|
||||||
} /*< switch (src_type) */
|
|
||||||
|
|
||||||
return_clonebuf:
|
return_clonebuf:
|
||||||
return clonebuf;
|
return clonebuf;
|
||||||
@ -329,6 +327,7 @@ bool gwbuf_set_type(
|
|||||||
case GWBUF_TYPE_MYSQL:
|
case GWBUF_TYPE_MYSQL:
|
||||||
case GWBUF_TYPE_PLAINSQL:
|
case GWBUF_TYPE_PLAINSQL:
|
||||||
case GWBUF_TYPE_UNDEFINED:
|
case GWBUF_TYPE_UNDEFINED:
|
||||||
|
case GWBUF_TYPE_SINGLE_STMT: /*< buffer contains one stmt */
|
||||||
buf->gwbuf_type |= type;
|
buf->gwbuf_type |= type;
|
||||||
succp = true;
|
succp = true;
|
||||||
break;
|
break;
|
||||||
|
@ -301,8 +301,9 @@ dcb_final_free(DCB *dcb)
|
|||||||
DCB_CALLBACK *cb;
|
DCB_CALLBACK *cb;
|
||||||
|
|
||||||
CHK_DCB(dcb);
|
CHK_DCB(dcb);
|
||||||
ss_info_dassert(dcb->state == DCB_STATE_DISCONNECTED,
|
ss_info_dassert(dcb->state == DCB_STATE_DISCONNECTED ||
|
||||||
"dcb not in DCB_STATE_DISCONNECTED state.");
|
dcb->state == DCB_STATE_ALLOC,
|
||||||
|
"dcb not in DCB_STATE_DISCONNECTED not in DCB_STATE_ALLOC state.");
|
||||||
|
|
||||||
/*< First remove this DCB from the chain */
|
/*< First remove this DCB from the chain */
|
||||||
spinlock_acquire(&dcbspin);
|
spinlock_acquire(&dcbspin);
|
||||||
@ -701,6 +702,11 @@ int dcb_read(
|
|||||||
n = 0;
|
n = 0;
|
||||||
goto return_n;
|
goto return_n;
|
||||||
}
|
}
|
||||||
|
else if (b == 0)
|
||||||
|
{
|
||||||
|
n = 0;
|
||||||
|
goto return_n;
|
||||||
|
}
|
||||||
bufsize = MIN(b, MAX_BUFFER_SIZE);
|
bufsize = MIN(b, MAX_BUFFER_SIZE);
|
||||||
|
|
||||||
if ((buffer = gwbuf_alloc(bufsize)) == NULL)
|
if ((buffer = gwbuf_alloc(bufsize)) == NULL)
|
||||||
|
@ -116,7 +116,8 @@ MODULE_INFO *mod_info = NULL;
|
|||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Error : Unable to load library for module: "
|
"Error : Unable to load library for module: "
|
||||||
"%s\n\t\t\t %s.",
|
"%s\n\n\t\t %s."
|
||||||
|
"\n\n",
|
||||||
module,
|
module,
|
||||||
dlerror())));
|
dlerror())));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -127,7 +127,8 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
|||||||
* session, therefore it is important that the session lock is
|
* session, therefore it is important that the session lock is
|
||||||
* relinquished beforethe router call.
|
* relinquished beforethe router call.
|
||||||
*/
|
*/
|
||||||
if (client_dcb->state != DCB_STATE_LISTENING && client_dcb->dcb_role != DCB_ROLE_INTERNAL)
|
if (client_dcb->state != DCB_STATE_LISTENING &&
|
||||||
|
client_dcb->dcb_role != DCB_ROLE_INTERNAL)
|
||||||
{
|
{
|
||||||
session->router_session =
|
session->router_session =
|
||||||
service->router->newSession(service->router_instance,
|
service->router->newSession(service->router_instance,
|
||||||
@ -196,6 +197,20 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
spinlock_acquire(&session_spin);
|
spinlock_acquire(&session_spin);
|
||||||
|
|
||||||
|
if (session->state != SESSION_STATE_READY)
|
||||||
|
{
|
||||||
|
session_free(session);
|
||||||
|
client_dcb->session = NULL;
|
||||||
|
session = NULL;
|
||||||
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
|
LOGFILE_ERROR,
|
||||||
|
"Error : Failed to create %s session.",
|
||||||
|
service->name)));
|
||||||
|
spinlock_release(&session_spin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
session->state = SESSION_STATE_ROUTER_READY;
|
session->state = SESSION_STATE_ROUTER_READY;
|
||||||
session->next = allSessions;
|
session->next = allSessions;
|
||||||
allSessions = session;
|
allSessions = session;
|
||||||
@ -203,7 +218,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
|||||||
atomic_add(&service->stats.n_sessions, 1);
|
atomic_add(&service->stats.n_sessions, 1);
|
||||||
atomic_add(&service->stats.n_current, 1);
|
atomic_add(&service->stats.n_current, 1);
|
||||||
CHK_SESSION(session);
|
CHK_SESSION(session);
|
||||||
|
}
|
||||||
return_session:
|
return_session:
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@ -310,9 +325,6 @@ bool session_free(
|
|||||||
|
|
||||||
/* Free router_session and session */
|
/* Free router_session and session */
|
||||||
if (session->router_session) {
|
if (session->router_session) {
|
||||||
session->service->router->closeSession(
|
|
||||||
session->service->router_instance,
|
|
||||||
session->router_session);
|
|
||||||
session->service->router->freeSession(
|
session->service->router->freeSession(
|
||||||
session->service->router_instance,
|
session->service->router_instance,
|
||||||
session->router_session);
|
session->router_session);
|
||||||
|
@ -48,11 +48,14 @@ typedef enum
|
|||||||
{
|
{
|
||||||
GWBUF_TYPE_UNDEFINED = 0x00,
|
GWBUF_TYPE_UNDEFINED = 0x00,
|
||||||
GWBUF_TYPE_PLAINSQL = 0x01,
|
GWBUF_TYPE_PLAINSQL = 0x01,
|
||||||
GWBUF_TYPE_MYSQL = 0x02
|
GWBUF_TYPE_MYSQL = 0x02,
|
||||||
|
GWBUF_TYPE_SINGLE_STMT = 0x04
|
||||||
} gwbuf_type_t;
|
} gwbuf_type_t;
|
||||||
|
|
||||||
|
#define GWBUF_IS_TYPE_UNDEFINED(b) (b->gwbuf_type == 0)
|
||||||
#define GWBUF_IS_TYPE_PLAINSQL(b) (b->gwbuf_type & GWBUF_TYPE_PLAINSQL)
|
#define GWBUF_IS_TYPE_PLAINSQL(b) (b->gwbuf_type & GWBUF_TYPE_PLAINSQL)
|
||||||
#define GWBUF_IS_TYPE_MYSQL(b) (b->gwbuf_type & GWBUF_TYPE_MYSQL)
|
#define GWBUF_IS_TYPE_MYSQL(b) (b->gwbuf_type & GWBUF_TYPE_MYSQL)
|
||||||
|
#define GWBUF_IS_TYPE_SINGLE_STMT(b) (b->gwbuf_type & GWBUF_TYPE_SINGLE_STMT)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A structure to encapsulate the data in a form that the data itself can be
|
* A structure to encapsulate the data in a form that the data itself can be
|
||||||
|
@ -229,7 +229,6 @@ typedef struct dcb {
|
|||||||
struct service *service; /**< The related service */
|
struct service *service; /**< The related service */
|
||||||
void *data; /**< Specific client data */
|
void *data; /**< Specific client data */
|
||||||
DCBMM memdata; /**< The data related to DCB memory management */
|
DCBMM memdata; /**< The data related to DCB memory management */
|
||||||
int command; /**< Specific client command type */
|
|
||||||
SPINLOCK cb_lock; /**< The lock for the callbacks linked list */
|
SPINLOCK cb_lock; /**< The lock for the callbacks linked list */
|
||||||
DCB_CALLBACK *callbacks; /**< The list of callbacks for the DCB */
|
DCB_CALLBACK *callbacks; /**< The list of callbacks for the DCB */
|
||||||
|
|
||||||
|
@ -98,35 +98,9 @@ typedef enum {
|
|||||||
MYSQL_AUTH_SENT,
|
MYSQL_AUTH_SENT,
|
||||||
MYSQL_AUTH_RECV,
|
MYSQL_AUTH_RECV,
|
||||||
MYSQL_AUTH_FAILED,
|
MYSQL_AUTH_FAILED,
|
||||||
MYSQL_IDLE,
|
MYSQL_IDLE
|
||||||
MYSQL_ROUTING,
|
} mysql_auth_state_t;
|
||||||
MYSQL_WAITING_RESULT,
|
|
||||||
MYSQL_SESSION_CHANGE
|
|
||||||
} mysql_pstate_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MySQL Protocol specific state data
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
skygw_chk_t protocol_chk_top;
|
|
||||||
#endif
|
|
||||||
int fd; /*< The socket descriptor */
|
|
||||||
struct dcb *owner_dcb; /*< The DCB of the socket
|
|
||||||
* we are running on */
|
|
||||||
mysql_pstate_t state; /*< Current protocol state */
|
|
||||||
uint8_t scramble[MYSQL_SCRAMBLE_LEN]; /*< server scramble,
|
|
||||||
* created or received */
|
|
||||||
uint32_t server_capabilities; /*< server capabilities,
|
|
||||||
* created or received */
|
|
||||||
uint32_t client_capabilities; /*< client capabilities,
|
|
||||||
* created or received */
|
|
||||||
unsigned long tid; /*< MySQL Thread ID, in
|
|
||||||
* handshake */
|
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
skygw_chk_t protocol_chk_tail;
|
|
||||||
#endif
|
|
||||||
} MySQLProtocol;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MySQL session specific data
|
* MySQL session specific data
|
||||||
@ -139,7 +113,6 @@ typedef struct mysql_session {
|
|||||||
} MYSQL_session;
|
} MYSQL_session;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Protocol packing macros. */
|
/** Protocol packing macros. */
|
||||||
#define gw_mysql_set_byte2(__buffer, __int) do { \
|
#define gw_mysql_set_byte2(__buffer, __int) do { \
|
||||||
(__buffer)[0]= (uint8_t)((__int) & 0xFF); \
|
(__buffer)[0]= (uint8_t)((__int) & 0xFF); \
|
||||||
@ -230,18 +203,90 @@ typedef enum
|
|||||||
),
|
),
|
||||||
} gw_mysql_capabilities_t;
|
} gw_mysql_capabilities_t;
|
||||||
|
|
||||||
/** Basic mysql commands */
|
/** Copy from enum in mariadb-5.5 mysql_com.h */
|
||||||
#define MYSQL_COM_CHANGE_USER 0x11
|
typedef enum mysql_server_cmd {
|
||||||
#define MYSQL_COM_QUIT 0x1
|
MYSQL_COM_UNDEFINED = -1,
|
||||||
#define MYSQL_COM_INIT_DB 0x2
|
MYSQL_COM_SLEEP = 0,
|
||||||
#define MYSQL_COM_QUERY 0x3
|
MYSQL_COM_QUIT,
|
||||||
|
MYSQL_COM_INIT_DB,
|
||||||
|
MYSQL_COM_QUERY,
|
||||||
|
MYSQL_COM_FIELD_LIST,
|
||||||
|
MYSQL_COM_CREATE_DB,
|
||||||
|
MYSQL_COM_DROP_DB,
|
||||||
|
MYSQL_COM_REFRESH,
|
||||||
|
MYSQL_COM_SHUTDOWN,
|
||||||
|
MYSQL_COM_STATISTICS,
|
||||||
|
MYSQL_COM_PROCESS_INFO,
|
||||||
|
MYSQL_COM_CONNECT,
|
||||||
|
MYSQL_COM_PROCESS_KILL,
|
||||||
|
MYSQL_COM_DEBUG,
|
||||||
|
MYSQL_COM_PING,
|
||||||
|
MYSQL_COM_TIME,
|
||||||
|
MYSQL_COM_DELAYED_INSERT,
|
||||||
|
MYSQL_COM_CHANGE_USER,
|
||||||
|
MYSQL_COM_BINLOG_DUMP,
|
||||||
|
MYSQL_COM_TABLE_DUMP,
|
||||||
|
MYSQL_COM_CONNECT_OUT,
|
||||||
|
MYSQL_COM_REGISTER_SLAVE,
|
||||||
|
MYSQL_COM_STMT_PREPARE,
|
||||||
|
MYSQL_COM_STMT_EXECUTE,
|
||||||
|
MYSQL_COM_STMT_SEND_LONG_DATA,
|
||||||
|
MYSQL_COM_STMT_CLOSE,
|
||||||
|
MYSQL_COM_STMT_RESET,
|
||||||
|
MYSQL_COM_SET_OPTION,
|
||||||
|
MYSQL_COM_STMT_FETCH,
|
||||||
|
MYSQL_COM_DAEMON
|
||||||
|
} mysql_server_cmd_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of server commands, and number of response packets are stored here.
|
||||||
|
* server_command_t is used in MySQLProtocol structure, so for each DCB there is
|
||||||
|
* one MySQLProtocol and one server command list.
|
||||||
|
*/
|
||||||
|
typedef struct server_command_st {
|
||||||
|
mysql_server_cmd_t cmd;
|
||||||
|
int nresponse_packets; /** filled when reply arrives */
|
||||||
|
struct server_command_st* next;
|
||||||
|
} server_command_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MySQL Protocol specific state data
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
skygw_chk_t protocol_chk_top;
|
||||||
|
#endif
|
||||||
|
int fd; /*< The socket descriptor */
|
||||||
|
struct dcb *owner_dcb; /*< The DCB of the socket
|
||||||
|
* we are running on */
|
||||||
|
SPINLOCK protocol_lock;
|
||||||
|
server_command_t protocol_command; /*< list of active commands */
|
||||||
|
mysql_auth_state_t protocol_auth_state; /*< Authentication status */
|
||||||
|
uint8_t scramble[MYSQL_SCRAMBLE_LEN]; /*< server scramble,
|
||||||
|
* created or received */
|
||||||
|
uint32_t server_capabilities; /*< server capabilities,
|
||||||
|
* created or received */
|
||||||
|
uint32_t client_capabilities; /*< client capabilities,
|
||||||
|
* created or received */
|
||||||
|
unsigned long tid; /*< MySQL Thread ID, in
|
||||||
|
* handshake */
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
skygw_chk_t protocol_chk_tail;
|
||||||
|
#endif
|
||||||
|
} MySQLProtocol;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MYSQL_GET_COMMAND(payload) (payload[4])
|
#define MYSQL_GET_COMMAND(payload) (payload[4])
|
||||||
#define MYSQL_GET_PACKET_NO(payload) (payload[3])
|
#define MYSQL_GET_PACKET_NO(payload) (payload[3])
|
||||||
#define MYSQL_GET_PACKET_LEN(payload) (gw_mysql_get_byte3(payload))
|
#define MYSQL_GET_PACKET_LEN(payload) (gw_mysql_get_byte3(payload))
|
||||||
#define MYSQL_GET_ERRCODE(payload) (gw_mysql_get_byte2(&payload[5]))
|
#define MYSQL_GET_ERRCODE(payload) (gw_mysql_get_byte2(&payload[5]))
|
||||||
|
#define MYSQL_GET_STMTOK_NPARAM(payload) (gw_mysql_get_byte2(&payload[9]))
|
||||||
|
#define MYSQL_GET_STMTOK_NATTR(payload) (gw_mysql_get_byte2(&payload[11]))
|
||||||
|
#define MYSQL_IS_ERROR_PACKET(payload) (MYSQL_GET_COMMAND(payload)==0xff)
|
||||||
|
|
||||||
#endif
|
#endif /** _MYSQL_PROTOCOL_H */
|
||||||
|
|
||||||
void gw_mysql_close(MySQLProtocol **ptr);
|
void gw_mysql_close(MySQLProtocol **ptr);
|
||||||
MySQLProtocol* mysql_protocol_init(DCB* dcb, int fd);
|
MySQLProtocol* mysql_protocol_init(DCB* dcb, int fd);
|
||||||
@ -314,4 +359,14 @@ char *gw_strend(register const char *s);
|
|||||||
int setnonblocking(int fd);
|
int setnonblocking(int fd);
|
||||||
int setipaddress(struct in_addr *a, char *p);
|
int setipaddress(struct in_addr *a, char *p);
|
||||||
GWBUF* gw_MySQL_get_next_packet(GWBUF** p_readbuf);
|
GWBUF* gw_MySQL_get_next_packet(GWBUF** p_readbuf);
|
||||||
|
GWBUF* gw_MySQL_get_packets(GWBUF** p_readbuf, int* npackets);
|
||||||
|
GWBUF* gw_MySQL_discard_packets(GWBUF* buf, int npackets);
|
||||||
|
void protocol_add_srv_command(MySQLProtocol* p, mysql_server_cmd_t cmd);
|
||||||
|
void protocol_remove_srv_command(MySQLProtocol* p);
|
||||||
|
bool protocol_waits_response(MySQLProtocol* p);
|
||||||
|
mysql_server_cmd_t protocol_get_srv_command(MySQLProtocol* p,bool removep);
|
||||||
|
int get_stmt_nresponse_packets(GWBUF* buf, mysql_server_cmd_t cmd);
|
||||||
|
int protocol_get_nresponse_packets (MySQLProtocol* p);
|
||||||
|
bool protocol_set_nresponse_packets (MySQLProtocol* p, int nresponse_packets);
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,15 +30,33 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dcb.h>
|
#include <dcb.h>
|
||||||
|
#include <hashtable.h>
|
||||||
|
|
||||||
|
#undef PREP_STMT_CACHING
|
||||||
|
|
||||||
|
#if defined(PREP_STMT_CACHING)
|
||||||
|
|
||||||
|
typedef enum prep_stmt_type {
|
||||||
|
PREP_STMT_NAME,
|
||||||
|
PREP_STMT_ID
|
||||||
|
} prep_stmt_type_t;
|
||||||
|
|
||||||
|
typedef enum prep_stmt_state {
|
||||||
|
PREP_STMT_ALLOC,
|
||||||
|
PREP_STMT_SENT,
|
||||||
|
PREP_STMT_RECV,
|
||||||
|
PREP_STMT_DROPPED
|
||||||
|
} prep_stmt_state_t;
|
||||||
|
|
||||||
|
#endif /*< PREP_STMT_CACHING */
|
||||||
|
|
||||||
typedef enum bref_state {
|
typedef enum bref_state {
|
||||||
BREF_NOT_USED = 0x00,
|
|
||||||
BREF_IN_USE = 0x01,
|
BREF_IN_USE = 0x01,
|
||||||
BREF_WAITING_RESULT = 0x02, /*< for anything that responds */
|
BREF_WAITING_RESULT = 0x02, /*< for anything that responds */
|
||||||
BREF_CLOSED = 0x04
|
BREF_CLOSED = 0x04
|
||||||
} bref_state_t;
|
} bref_state_t;
|
||||||
|
|
||||||
#define BREF_IS_NOT_USED(s) (s->bref_state & BREF_NOT_USED)
|
#define BREF_IS_NOT_USED(s) (s->bref_state & ~BREF_IN_USE)
|
||||||
#define BREF_IS_IN_USE(s) (s->bref_state & BREF_IN_USE)
|
#define BREF_IS_IN_USE(s) (s->bref_state & BREF_IN_USE)
|
||||||
#define BREF_IS_WAITING_RESULT(s) (s->bref_state & BREF_WAITING_RESULT)
|
#define BREF_IS_WAITING_RESULT(s) (s->bref_state & BREF_WAITING_RESULT)
|
||||||
#define BREF_IS_CLOSED(s) (s->bref_state & BREF_CLOSED)
|
#define BREF_IS_CLOSED(s) (s->bref_state & BREF_CLOSED)
|
||||||
@ -186,6 +204,25 @@ typedef struct rwsplit_config_st {
|
|||||||
} rwsplit_config_t;
|
} rwsplit_config_t;
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(PREP_STMT_CACHING)
|
||||||
|
|
||||||
|
typedef struct prep_stmt_st {
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
skygw_chk_t pstmt_chk_top;
|
||||||
|
#endif
|
||||||
|
union id {
|
||||||
|
int seq;
|
||||||
|
char* name;
|
||||||
|
} pstmt_id;
|
||||||
|
prep_stmt_state_t pstmt_state;
|
||||||
|
prep_stmt_type_t pstmt_type;
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
skygw_chk_t pstmt_chk_tail;
|
||||||
|
#endif
|
||||||
|
} prep_stmt_t;
|
||||||
|
|
||||||
|
#endif /*< PREP_STMT_CACHING */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The client session structure used within this router.
|
* The client session structure used within this router.
|
||||||
*/
|
*/
|
||||||
@ -205,7 +242,9 @@ struct router_client_session {
|
|||||||
int rses_capabilities; /*< input type, for example */
|
int rses_capabilities; /*< input type, for example */
|
||||||
bool rses_autocommit_enabled;
|
bool rses_autocommit_enabled;
|
||||||
bool rses_transaction_active;
|
bool rses_transaction_active;
|
||||||
uint64_t rses_id; /*< ID for router client session */
|
#if defined(PREP_STMT_CACHING)
|
||||||
|
HASHTABLE* rses_prep_stmt[2];
|
||||||
|
#endif
|
||||||
struct router_client_session* next;
|
struct router_client_session* next;
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
skygw_chk_t rses_chk_tail;
|
skygw_chk_t rses_chk_tail;
|
||||||
|
@ -163,7 +163,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
|
|
||||||
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
||||||
CHK_PROTOCOL(backend_protocol);
|
CHK_PROTOCOL(backend_protocol);
|
||||||
|
#if 1
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_event] Read dcb %p fd %d protocol "
|
"%lu [gw_read_backend_event] Read dcb %p fd %d protocol "
|
||||||
@ -171,8 +171,9 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
pthread_self(),
|
pthread_self(),
|
||||||
dcb,
|
dcb,
|
||||||
dcb->fd,
|
dcb->fd,
|
||||||
backend_protocol->state,
|
backend_protocol->protocol_auth_state,
|
||||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* backend is connected:
|
/* backend is connected:
|
||||||
@ -186,17 +187,18 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
* If starting to auhenticate with backend server, lock dcb
|
* If starting to auhenticate with backend server, lock dcb
|
||||||
* to prevent overlapping processing of auth messages.
|
* to prevent overlapping processing of auth messages.
|
||||||
*/
|
*/
|
||||||
if (backend_protocol->state == MYSQL_CONNECTED) {
|
if (backend_protocol->protocol_auth_state == MYSQL_CONNECTED)
|
||||||
|
{
|
||||||
spinlock_acquire(&dcb->authlock);
|
spinlock_acquire(&dcb->authlock);
|
||||||
|
|
||||||
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
||||||
CHK_PROTOCOL(backend_protocol);
|
CHK_PROTOCOL(backend_protocol);
|
||||||
|
|
||||||
if (backend_protocol->state == MYSQL_CONNECTED) {
|
if (backend_protocol->protocol_auth_state == MYSQL_CONNECTED)
|
||||||
|
{
|
||||||
if (gw_read_backend_handshake(backend_protocol) != 0) {
|
if (gw_read_backend_handshake(backend_protocol) != 0)
|
||||||
backend_protocol->state = MYSQL_AUTH_FAILED;
|
{
|
||||||
|
backend_protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_event] after "
|
"%lu [gw_read_backend_event] after "
|
||||||
@ -205,7 +207,9 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
pthread_self(),
|
pthread_self(),
|
||||||
backend_protocol->owner_dcb->fd)));
|
backend_protocol->owner_dcb->fd)));
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* handshake decoded, send the auth credentials */
|
/* handshake decoded, send the auth credentials */
|
||||||
if (gw_send_authentication_to_backend(
|
if (gw_send_authentication_to_backend(
|
||||||
current_session->db,
|
current_session->db,
|
||||||
@ -213,7 +217,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
current_session->client_sha1,
|
current_session->client_sha1,
|
||||||
backend_protocol) != 0)
|
backend_protocol) != 0)
|
||||||
{
|
{
|
||||||
backend_protocol->state = MYSQL_AUTH_FAILED;
|
backend_protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_event] after "
|
"%lu [gw_read_backend_event] after "
|
||||||
@ -221,31 +225,31 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
"fd %d, state = MYSQL_AUTH_FAILED.",
|
"fd %d, state = MYSQL_AUTH_FAILED.",
|
||||||
pthread_self(),
|
pthread_self(),
|
||||||
backend_protocol->owner_dcb->fd)));
|
backend_protocol->owner_dcb->fd)));
|
||||||
} else {
|
}
|
||||||
backend_protocol->state = MYSQL_AUTH_RECV;
|
else
|
||||||
|
{
|
||||||
|
backend_protocol->protocol_auth_state = MYSQL_AUTH_RECV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spinlock_release(&dcb->authlock);
|
spinlock_release(&dcb->authlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now:
|
* Now:
|
||||||
* -- check the authentication reply from backend
|
* -- check the authentication reply from backend
|
||||||
* OR
|
* OR
|
||||||
* -- handle a previous handshake error
|
* -- handle a previous handshake error
|
||||||
*/
|
*/
|
||||||
if (backend_protocol->state == MYSQL_AUTH_RECV ||
|
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV ||
|
||||||
backend_protocol->state == MYSQL_AUTH_FAILED)
|
backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED)
|
||||||
{
|
{
|
||||||
spinlock_acquire(&dcb->authlock);
|
spinlock_acquire(&dcb->authlock);
|
||||||
|
|
||||||
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
||||||
CHK_PROTOCOL(backend_protocol);
|
CHK_PROTOCOL(backend_protocol);
|
||||||
|
|
||||||
if (backend_protocol->state == MYSQL_AUTH_RECV ||
|
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV ||
|
||||||
backend_protocol->state == MYSQL_AUTH_FAILED)
|
backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED)
|
||||||
{
|
{
|
||||||
ROUTER_OBJECT *router = NULL;
|
ROUTER_OBJECT *router = NULL;
|
||||||
ROUTER *router_instance = NULL;
|
ROUTER *router_instance = NULL;
|
||||||
@ -259,7 +263,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
router_instance = session->service->router_instance;
|
router_instance = session->service->router_instance;
|
||||||
rsession = session->router_session;
|
rsession = session->router_session;
|
||||||
|
|
||||||
if (backend_protocol->state == MYSQL_AUTH_RECV) {
|
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_RECV) {
|
||||||
/*<
|
/*<
|
||||||
* Read backed auth reply
|
* Read backed auth reply
|
||||||
*/
|
*/
|
||||||
@ -268,14 +272,14 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
|
|
||||||
switch (receive_rc) {
|
switch (receive_rc) {
|
||||||
case -1:
|
case -1:
|
||||||
backend_protocol->state = MYSQL_AUTH_FAILED;
|
backend_protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_event] after "
|
"%lu [gw_read_backend_event] after "
|
||||||
"gw_receive_backend_authentication "
|
"gw_receive_backend_authentication "
|
||||||
"fd %d, state = MYSQL_AUTH_FAILED.",
|
"fd %d, state = MYSQL_AUTH_FAILED.",
|
||||||
backend_protocol->owner_dcb->fd,
|
pthread_self(),
|
||||||
pthread_self())));
|
backend_protocol->owner_dcb->fd)));
|
||||||
|
|
||||||
|
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
@ -286,7 +290,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
current_session->user)));
|
current_session->user)));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
backend_protocol->state = MYSQL_IDLE;
|
backend_protocol->protocol_auth_state = MYSQL_IDLE;
|
||||||
|
|
||||||
LOGIF(LD, (skygw_log_write_flush(
|
LOGIF(LD, (skygw_log_write_flush(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
@ -316,7 +320,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
} /* switch */
|
} /* switch */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backend_protocol->state == MYSQL_AUTH_FAILED)
|
if (backend_protocol->protocol_auth_state == MYSQL_AUTH_FAILED)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* protocol state won't change anymore,
|
* protocol state won't change anymore,
|
||||||
@ -340,9 +344,14 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
/* try reload users' table for next connection */
|
/* try reload users' table for next connection */
|
||||||
service_refresh_users(dcb->session->service);
|
service_refresh_users(dcb->session->service);
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_DEBUG,
|
||||||
"Backend read error handling.")));
|
"%lu [gw_read_backend_event] "
|
||||||
|
"calling handleError. Backend "
|
||||||
|
"DCB %p, session %p",
|
||||||
|
pthread_self(),
|
||||||
|
dcb,
|
||||||
|
dcb->session)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
errbuf = mysql_create_custom_error(
|
errbuf = mysql_create_custom_error(
|
||||||
@ -360,6 +369,15 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
|
|
||||||
ss_dassert(!succp);
|
ss_dassert(!succp);
|
||||||
|
|
||||||
|
LOGIF(LD, (skygw_log_write(
|
||||||
|
LOGFILE_DEBUG,
|
||||||
|
"%lu [gw_read_backend_event] "
|
||||||
|
"after calling handleError. Backend "
|
||||||
|
"DCB %p, session %p",
|
||||||
|
pthread_self(),
|
||||||
|
dcb,
|
||||||
|
dcb->session)));
|
||||||
|
|
||||||
if (session != NULL)
|
if (session != NULL)
|
||||||
{
|
{
|
||||||
spinlock_acquire(&session->ses_lock);
|
spinlock_acquire(&session->ses_lock);
|
||||||
@ -373,7 +391,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ss_dassert(backend_protocol->state == MYSQL_IDLE);
|
ss_dassert(backend_protocol->protocol_auth_state == MYSQL_IDLE);
|
||||||
LOGIF(LD, (skygw_log_write_flush(
|
LOGIF(LD, (skygw_log_write_flush(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_event] "
|
"%lu [gw_read_backend_event] "
|
||||||
@ -398,11 +416,13 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
|
|
||||||
/* reading MySQL command output from backend and writing to the client */
|
/* reading MySQL command output from backend and writing to the client */
|
||||||
{
|
{
|
||||||
GWBUF *writebuf = NULL;
|
GWBUF *readbuf = NULL;
|
||||||
ROUTER_OBJECT *router = NULL;
|
ROUTER_OBJECT *router = NULL;
|
||||||
ROUTER *router_instance = NULL;
|
ROUTER *router_instance = NULL;
|
||||||
void *rsession = NULL;
|
void *rsession = NULL;
|
||||||
SESSION *session = dcb->session;
|
SESSION *session = dcb->session;
|
||||||
|
int nbytes_read = 0;
|
||||||
|
mysql_server_cmd_t srvcmd = MYSQL_COM_UNDEFINED;
|
||||||
|
|
||||||
CHK_SESSION(session);
|
CHK_SESSION(session);
|
||||||
router = session->service->router;
|
router = session->service->router;
|
||||||
@ -410,32 +430,17 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
rsession = session->router_session;
|
rsession = session->router_session;
|
||||||
|
|
||||||
/* read available backend data */
|
/* read available backend data */
|
||||||
rc = dcb_read(dcb, &writebuf);
|
rc = dcb_read(dcb, &readbuf);
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
{
|
{
|
||||||
/*< vraa : errorHandle */
|
|
||||||
/*<
|
|
||||||
* Backend generated EPOLLIN event and if backend has
|
|
||||||
* failed, connection must be closed to avoid backend
|
|
||||||
* dcb from getting hanged.
|
|
||||||
*/
|
|
||||||
GWBUF* errbuf;
|
GWBUF* errbuf;
|
||||||
bool succp;
|
bool succp;
|
||||||
/**
|
|
||||||
* - send error for client
|
|
||||||
* - mark failed backend BREF_NOT_USED
|
|
||||||
* - go through all servers and select one according to
|
|
||||||
* the criteria that user specified in the beginning.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Backend read error handling #2.")));
|
"Backend read error handling #2.")));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
errbuf = mysql_create_custom_error(
|
errbuf = mysql_create_custom_error(
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
@ -458,33 +463,111 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
rc = 0;
|
rc = 0;
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
}
|
||||||
|
nbytes_read = gwbuf_length(readbuf);
|
||||||
|
|
||||||
if (writebuf == NULL) {
|
if (nbytes_read == 0)
|
||||||
rc = 0;
|
{
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss_dassert(readbuf != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ask for next response (1 or more packets) like in
|
||||||
|
* gw_MySQL_get_next_packet but gw_MySQL_get_next_response
|
||||||
|
*/
|
||||||
|
srvcmd = protocol_get_srv_command((MySQLProtocol *)dcb->protocol,
|
||||||
|
false);
|
||||||
|
/**
|
||||||
|
* If backend DCB is waiting for response to COM_STMT_PREPARE,
|
||||||
|
* it, then only that must be passed to clientReply.
|
||||||
|
*
|
||||||
|
* If response consists of ses cmd response and response to
|
||||||
|
* COM_STMT_PREPARE, there can't be anything after
|
||||||
|
* COM_STMT_PREPARE response because whole buffer may be
|
||||||
|
* discarded since router doesn't know the borderlines of MySQL
|
||||||
|
* packets.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read all packets from <readbuf> which belong to STMT PREPARE
|
||||||
|
* response.
|
||||||
|
* Move packets not belonging to STMT PREPARE response to
|
||||||
|
* dcb_readqueue.
|
||||||
|
* When whole response is read, pass <readbuf> forward to
|
||||||
|
* clientReply.
|
||||||
|
*/
|
||||||
|
if (srvcmd == MYSQL_COM_STMT_PREPARE)
|
||||||
|
{
|
||||||
|
MySQLProtocol* p;
|
||||||
|
int nresponse_packets;
|
||||||
|
GWBUF* tmpbuf;
|
||||||
|
|
||||||
|
p = (MySQLProtocol *)dcb->protocol;
|
||||||
|
nresponse_packets = protocol_get_nresponse_packets(p);
|
||||||
|
|
||||||
|
/** count only once per response */
|
||||||
|
if (nresponse_packets == 0)
|
||||||
|
{
|
||||||
|
nresponse_packets = get_stmt_nresponse_packets(
|
||||||
|
readbuf,
|
||||||
|
srvcmd);
|
||||||
|
}
|
||||||
|
tmpbuf = gw_MySQL_get_packets(&readbuf, &nresponse_packets);
|
||||||
|
gwbuf_append(dcb->dcb_readqueue, readbuf);
|
||||||
|
readbuf = tmpbuf;
|
||||||
|
|
||||||
|
/** <readbuf> contains incomplete response to STMT PREPARE */
|
||||||
|
if (nresponse_packets != 0)
|
||||||
|
{
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Backend fd %d read incomplete response packet. "
|
||||||
|
"Waiting %d more, cmd %s.",
|
||||||
|
dcb->fd,
|
||||||
|
nresponse_packets,
|
||||||
|
STRPACKETTYPE(srvcmd))));
|
||||||
|
/**
|
||||||
|
* store the number of how many packets the
|
||||||
|
* reponse consists of to backend's protocol.
|
||||||
|
*/
|
||||||
|
protocol_set_nresponse_packets(p, nresponse_packets);
|
||||||
|
goto return_rc;
|
||||||
|
}
|
||||||
|
protocol_remove_srv_command((MySQLProtocol *)dcb->protocol);
|
||||||
|
}
|
||||||
/*<
|
/*<
|
||||||
* If dcb->session->client is freed already it may be NULL.
|
* If dcb->session->client is freed already it may be NULL.
|
||||||
*/
|
*/
|
||||||
if (dcb->session->client != NULL) {
|
if (dcb->session->client != NULL)
|
||||||
|
{
|
||||||
client_protocol = SESSION_PROTOCOL(dcb->session,
|
client_protocol = SESSION_PROTOCOL(dcb->session,
|
||||||
MySQLProtocol);
|
MySQLProtocol);
|
||||||
if (client_protocol != NULL) {
|
if (client_protocol != NULL)
|
||||||
|
{
|
||||||
CHK_PROTOCOL(client_protocol);
|
CHK_PROTOCOL(client_protocol);
|
||||||
|
|
||||||
if (client_protocol->state == MYSQL_IDLE)
|
if (client_protocol->protocol_auth_state ==
|
||||||
|
MYSQL_IDLE)
|
||||||
{
|
{
|
||||||
gwbuf_set_type(writebuf, GWBUF_TYPE_MYSQL);
|
gwbuf_set_type(readbuf, GWBUF_TYPE_MYSQL);
|
||||||
|
|
||||||
router->clientReply(router_instance,
|
router->clientReply(router_instance,
|
||||||
rsession,
|
rsession,
|
||||||
writebuf,
|
readbuf,
|
||||||
dcb);
|
dcb);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
} else if (dcb->session->client->dcb_role == DCB_ROLE_INTERNAL) {
|
}
|
||||||
gwbuf_set_type(writebuf, GWBUF_TYPE_MYSQL);
|
else if (dcb->session->client->dcb_role == DCB_ROLE_INTERNAL)
|
||||||
router->clientReply(router_instance, rsession, writebuf, dcb);
|
{
|
||||||
|
gwbuf_set_type(readbuf, GWBUF_TYPE_MYSQL);
|
||||||
|
router->clientReply(router_instance, rsession, readbuf, dcb);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -550,8 +633,8 @@ static int gw_write_backend_event(DCB *dcb) {
|
|||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backend_protocol->state == MYSQL_PENDING_CONNECT) {
|
if (backend_protocol->protocol_auth_state == MYSQL_PENDING_CONNECT) {
|
||||||
backend_protocol->state = MYSQL_CONNECTED;
|
backend_protocol->protocol_auth_state = MYSQL_CONNECTED;
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
}
|
||||||
@ -571,7 +654,7 @@ return_rc:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write function for backend DCB
|
* Write function for backend DCB. Store command to protocol.
|
||||||
*
|
*
|
||||||
* @param dcb The DCB of the backend
|
* @param dcb The DCB of the backend
|
||||||
* @param queue Queue of buffers to write
|
* @param queue Queue of buffers to write
|
||||||
@ -589,7 +672,7 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
|||||||
* If auth failed, return value is 0, write and buffered write
|
* If auth failed, return value is 0, write and buffered write
|
||||||
* return 1.
|
* return 1.
|
||||||
*/
|
*/
|
||||||
switch(backend_protocol->state) {
|
switch(backend_protocol->protocol_auth_state) {
|
||||||
case MYSQL_AUTH_FAILED:
|
case MYSQL_AUTH_FAILED:
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -617,6 +700,10 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case MYSQL_IDLE:
|
case MYSQL_IDLE:
|
||||||
|
{
|
||||||
|
uint8_t* ptr = GWBUF_DATA(queue);
|
||||||
|
int cmd = MYSQL_GET_COMMAND(ptr);
|
||||||
|
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_MySQLWrite_backend] write to dcb %p "
|
"%lu [gw_MySQLWrite_backend] write to dcb %p "
|
||||||
@ -624,18 +711,37 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
|||||||
pthread_self(),
|
pthread_self(),
|
||||||
dcb,
|
dcb,
|
||||||
dcb->fd,
|
dcb->fd,
|
||||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||||
spinlock_release(&dcb->authlock);
|
spinlock_release(&dcb->authlock);
|
||||||
|
/**
|
||||||
|
* Server commands are stored to MySQLProtocol structure
|
||||||
|
* if buffer always includes a single statement. That
|
||||||
|
* information is stored in GWBUF type field
|
||||||
|
* (GWBUF_TYPE_SINGLE_STMT bit).
|
||||||
|
*/
|
||||||
|
if (GWBUF_IS_TYPE_SINGLE_STMT(queue))
|
||||||
|
{
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Write to backend's DCB fd %d "
|
||||||
|
"cmd %s protocol state %s.",
|
||||||
|
dcb->fd,
|
||||||
|
STRPACKETTYPE(cmd),
|
||||||
|
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||||
|
/** Record the command to backend's protocol */
|
||||||
|
protocol_add_srv_command(backend_protocol, cmd);
|
||||||
|
}
|
||||||
|
/** Write to backend */
|
||||||
rc = dcb_write(dcb, queue);
|
rc = dcb_write(dcb, queue);
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/*<
|
{
|
||||||
* Now put the incoming data to the delay queue unless backend is
|
uint8_t* ptr = GWBUF_DATA(queue);
|
||||||
* connected with auth ok
|
int cmd = MYSQL_GET_COMMAND(ptr);
|
||||||
*/
|
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_MySQLWrite_backend] delayed write to "
|
"%lu [gw_MySQLWrite_backend] delayed write to "
|
||||||
@ -643,13 +749,37 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
|||||||
pthread_self(),
|
pthread_self(),
|
||||||
dcb,
|
dcb,
|
||||||
dcb->fd,
|
dcb->fd,
|
||||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||||
|
/**
|
||||||
|
* Since it is known that buffer contains one complete
|
||||||
|
* command, store the command to backend's protocol. When
|
||||||
|
* backend server responses the command determines how
|
||||||
|
* response needs to be processed. This is mainly due to
|
||||||
|
* MYSQL_COM_STMT_PREPARE whose response consists of
|
||||||
|
* arbitrary number of packets.
|
||||||
|
*/
|
||||||
|
if (GWBUF_IS_TYPE_SINGLE_STMT(queue))
|
||||||
|
{
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Write to backend's delayqueue fd %d "
|
||||||
|
"protocol state %s.",
|
||||||
|
dcb->fd,
|
||||||
|
STRPROTOCOLSTATE(backend_protocol->protocol_auth_state))));
|
||||||
|
/** Record the command to backend's protocol */
|
||||||
|
protocol_add_srv_command(backend_protocol, cmd);
|
||||||
|
}
|
||||||
|
/*<
|
||||||
|
* Now put the incoming data to the delay queue unless backend is
|
||||||
|
* connected with auth ok
|
||||||
|
*/
|
||||||
backend_set_delayqueue(dcb, queue);
|
backend_set_delayqueue(dcb, queue);
|
||||||
spinlock_release(&dcb->authlock);
|
spinlock_release(&dcb->authlock);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return_rc:
|
return_rc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -757,7 +887,7 @@ static int gw_create_backend_connection(
|
|||||||
case 0:
|
case 0:
|
||||||
ss_dassert(fd > 0);
|
ss_dassert(fd > 0);
|
||||||
protocol->fd = fd;
|
protocol->fd = fd;
|
||||||
protocol->state = MYSQL_CONNECTED;
|
protocol->protocol_auth_state = MYSQL_CONNECTED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_create_backend_connection] Established "
|
"%lu [gw_create_backend_connection] Established "
|
||||||
@ -772,7 +902,7 @@ static int gw_create_backend_connection(
|
|||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
ss_dassert(fd > 0);
|
ss_dassert(fd > 0);
|
||||||
protocol->state = MYSQL_PENDING_CONNECT;
|
protocol->protocol_auth_state = MYSQL_PENDING_CONNECT;
|
||||||
protocol->fd = fd;
|
protocol->fd = fd;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
@ -787,7 +917,7 @@ static int gw_create_backend_connection(
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
ss_dassert(fd == -1);
|
ss_dassert(fd == -1);
|
||||||
ss_dassert(protocol->state == MYSQL_ALLOC);
|
ss_dassert(protocol->protocol_auth_state == MYSQL_ALLOC);
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_create_backend_connection] Connection "
|
"%lu [gw_create_backend_connection] Connection "
|
||||||
|
@ -587,7 +587,7 @@ int gw_read_client_event(
|
|||||||
/**
|
/**
|
||||||
* Now there should be at least one complete mysql packet in read_buffer.
|
* Now there should be at least one complete mysql packet in read_buffer.
|
||||||
*/
|
*/
|
||||||
switch (protocol->state) {
|
switch (protocol->protocol_auth_state) {
|
||||||
|
|
||||||
case MYSQL_AUTH_SENT:
|
case MYSQL_AUTH_SENT:
|
||||||
{
|
{
|
||||||
@ -600,7 +600,7 @@ int gw_read_client_event(
|
|||||||
if (auth_val == 0)
|
if (auth_val == 0)
|
||||||
{
|
{
|
||||||
SESSION *session = NULL;
|
SESSION *session = NULL;
|
||||||
protocol->state = MYSQL_AUTH_RECV;
|
protocol->protocol_auth_state = MYSQL_AUTH_RECV;
|
||||||
/**
|
/**
|
||||||
* Create session, and a router session for it.
|
* Create session, and a router session for it.
|
||||||
* If successful, there will be backend connection(s)
|
* If successful, there will be backend connection(s)
|
||||||
@ -612,7 +612,8 @@ int gw_read_client_event(
|
|||||||
{
|
{
|
||||||
CHK_SESSION(session);
|
CHK_SESSION(session);
|
||||||
ss_dassert(session->state != SESSION_STATE_ALLOC);
|
ss_dassert(session->state != SESSION_STATE_ALLOC);
|
||||||
protocol->state = MYSQL_IDLE;
|
|
||||||
|
protocol->protocol_auth_state = MYSQL_IDLE;
|
||||||
/**
|
/**
|
||||||
* Send an AUTH_OK packet to the client,
|
* Send an AUTH_OK packet to the client,
|
||||||
* packet sequence is # 2
|
* packet sequence is # 2
|
||||||
@ -621,7 +622,7 @@ int gw_read_client_event(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
protocol->state = MYSQL_AUTH_FAILED;
|
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_client_event] session "
|
"%lu [gw_read_client_event] session "
|
||||||
@ -642,7 +643,7 @@ int gw_read_client_event(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
protocol->state = MYSQL_AUTH_FAILED;
|
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_client_event] after "
|
"%lu [gw_read_client_event] after "
|
||||||
@ -894,7 +895,7 @@ int gw_write_client_event(DCB *dcb)
|
|||||||
protocol = (MySQLProtocol *)dcb->protocol;
|
protocol = (MySQLProtocol *)dcb->protocol;
|
||||||
CHK_PROTOCOL(protocol);
|
CHK_PROTOCOL(protocol);
|
||||||
|
|
||||||
if (protocol->state == MYSQL_IDLE)
|
if (protocol->protocol_auth_state == MYSQL_IDLE)
|
||||||
{
|
{
|
||||||
dcb_drain_writeq(dcb);
|
dcb_drain_writeq(dcb);
|
||||||
goto return_1;
|
goto return_1;
|
||||||
@ -1236,7 +1237,7 @@ int gw_MySQLAccept(DCB *listener)
|
|||||||
MySQLSendHandshake(client_dcb);
|
MySQLSendHandshake(client_dcb);
|
||||||
|
|
||||||
// client protocol state change
|
// client protocol state change
|
||||||
protocol->state = MYSQL_AUTH_SENT;
|
protocol->protocol_auth_state = MYSQL_AUTH_SENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set new descriptor to event set. At the same time,
|
* Set new descriptor to event set. At the same time,
|
||||||
@ -1294,8 +1295,15 @@ static int gw_error_client_event(
|
|||||||
SESSION* session;
|
SESSION* session;
|
||||||
|
|
||||||
CHK_DCB(dcb);
|
CHK_DCB(dcb);
|
||||||
session = dcb->session;
|
|
||||||
CHK_SESSION(session);
|
LOGIF(LD, (skygw_log_write(
|
||||||
|
LOGFILE_DEBUG,
|
||||||
|
"%lu [gw_error_client_event] Error event handling for DCB %p "
|
||||||
|
"in state %s, session %p.",
|
||||||
|
pthread_self(),
|
||||||
|
dcb,
|
||||||
|
STRDCBSTATE(dcb->state),
|
||||||
|
(session != NULL ? session : NULL))));
|
||||||
|
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
@ -1373,7 +1381,7 @@ gw_client_hangup_event(DCB *dcb)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect if buffer includes partial mysql packet or multiple packets.
|
* Detect if buffer includes partial mysql packet or multiple packets.
|
||||||
* Store partial packet to pendingqueue. Send complete packets one by one
|
* Store partial packet to dcb_readqueue. Send complete packets one by one
|
||||||
* to router.
|
* to router.
|
||||||
*
|
*
|
||||||
* It is assumed readbuf includes at least one complete packet.
|
* It is assumed readbuf includes at least one complete packet.
|
||||||
@ -1392,6 +1400,20 @@ static int route_by_statement(SESSION *session, GWBUF *readbuf)
|
|||||||
if (packetbuf != NULL)
|
if (packetbuf != NULL)
|
||||||
{
|
{
|
||||||
CHK_GWBUF(packetbuf);
|
CHK_GWBUF(packetbuf);
|
||||||
|
/**
|
||||||
|
* This means that buffer includes exactly one MySQL
|
||||||
|
* statement.
|
||||||
|
* backend func.write uses the information. MySQL backend
|
||||||
|
* protocol, for example, stores the command identifier
|
||||||
|
* to protocol structure. When some other thread reads
|
||||||
|
* the corresponding response the command tells how to
|
||||||
|
* handle response.
|
||||||
|
*
|
||||||
|
* Set it here instead of gw_read_client_event to make
|
||||||
|
* sure it is set to each (MySQL) packet.
|
||||||
|
*/
|
||||||
|
gwbuf_set_type(packetbuf, GWBUF_TYPE_SINGLE_STMT);
|
||||||
|
/** Route query */
|
||||||
rc = SESSION_ROUTE_QUERY(session, packetbuf);
|
rc = SESSION_ROUTE_QUERY(session, packetbuf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -76,7 +76,8 @@ MySQLProtocol* mysql_protocol_init(
|
|||||||
strerror(eno))));
|
strerror(eno))));
|
||||||
goto return_p;
|
goto return_p;
|
||||||
}
|
}
|
||||||
p->state = MYSQL_ALLOC;
|
p->protocol_auth_state = MYSQL_ALLOC;
|
||||||
|
p->protocol_command.cmd = MYSQL_COM_UNDEFINED;
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
p->protocol_chk_top = CHK_NUM_PROTOCOL;
|
p->protocol_chk_top = CHK_NUM_PROTOCOL;
|
||||||
p->protocol_chk_tail = CHK_NUM_PROTOCOL;
|
p->protocol_chk_tail = CHK_NUM_PROTOCOL;
|
||||||
@ -151,7 +152,7 @@ int gw_read_backend_handshake(
|
|||||||
|
|
||||||
if (h_len <= 4) {
|
if (h_len <= 4) {
|
||||||
/* log error this exit point */
|
/* log error this exit point */
|
||||||
conn->state = MYSQL_AUTH_FAILED;
|
conn->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_handshake] after "
|
"%lu [gw_read_backend_handshake] after "
|
||||||
@ -198,7 +199,7 @@ int gw_read_backend_handshake(
|
|||||||
* data in buffer less than expected in the
|
* data in buffer less than expected in the
|
||||||
* packet. Log error this exit point
|
* packet. Log error this exit point
|
||||||
*/
|
*/
|
||||||
conn->state = MYSQL_AUTH_FAILED;
|
conn->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_handshake] after "
|
"%lu [gw_read_backend_handshake] after "
|
||||||
@ -223,7 +224,7 @@ int gw_read_backend_handshake(
|
|||||||
* we cannot continue
|
* we cannot continue
|
||||||
* log error this exit point
|
* log error this exit point
|
||||||
*/
|
*/
|
||||||
conn->state = MYSQL_AUTH_FAILED;
|
conn->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_backend_handshake] after "
|
"%lu [gw_read_backend_handshake] after "
|
||||||
@ -236,7 +237,7 @@ int gw_read_backend_handshake(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->state = MYSQL_AUTH_SENT;
|
conn->protocol_auth_state = MYSQL_AUTH_SENT;
|
||||||
|
|
||||||
// consume all the data here
|
// consume all the data here
|
||||||
head = gwbuf_consume(head, GWBUF_LENGTH(head));
|
head = gwbuf_consume(head, GWBUF_LENGTH(head));
|
||||||
@ -789,13 +790,7 @@ gw_mysql_protocol_state2string (int state) {
|
|||||||
case MYSQL_AUTH_FAILED:
|
case MYSQL_AUTH_FAILED:
|
||||||
return "MySQL Authentication failed";
|
return "MySQL Authentication failed";
|
||||||
case MYSQL_IDLE:
|
case MYSQL_IDLE:
|
||||||
return "MySQL Auth done. Protocol is idle, waiting for statements";
|
return "MySQL authentication is succesfully done.";
|
||||||
case MYSQL_ROUTING:
|
|
||||||
return "MySQL received command has been routed to backend(s)";
|
|
||||||
case MYSQL_WAITING_RESULT:
|
|
||||||
return "MySQL Waiting for result set";
|
|
||||||
case MYSQL_SESSION_CHANGE:
|
|
||||||
return "MySQL change session";
|
|
||||||
default:
|
default:
|
||||||
return "MySQL (unknown protocol state)";
|
return "MySQL (unknown protocol state)";
|
||||||
}
|
}
|
||||||
@ -960,11 +955,9 @@ int mysql_send_custom_error (
|
|||||||
const char *mysql_message)
|
const char *mysql_message)
|
||||||
{
|
{
|
||||||
GWBUF* buf;
|
GWBUF* buf;
|
||||||
int nbytes;
|
|
||||||
|
|
||||||
buf = mysql_create_custom_error(dcb, in_affected_rows, mysql_message);
|
buf = mysql_create_custom_error(packet_number, in_affected_rows, mysql_message);
|
||||||
|
|
||||||
nbytes = GWBUF_LENGTH(buf);
|
|
||||||
dcb->func.write(dcb, buf);
|
dcb->func.write(dcb, buf);
|
||||||
|
|
||||||
return GWBUF_LENGTH(buf);
|
return GWBUF_LENGTH(buf);
|
||||||
@ -1500,7 +1493,7 @@ GWBUF* gw_MySQL_get_next_packet(
|
|||||||
packetbuf = NULL;
|
packetbuf = NULL;
|
||||||
goto return_packetbuf;
|
goto return_packetbuf;
|
||||||
}
|
}
|
||||||
|
/** there is one complete packet in the buffer */
|
||||||
if (packetlen == buflen)
|
if (packetlen == buflen)
|
||||||
{
|
{
|
||||||
packetbuf = gwbuf_clone_portion(readbuf, 0, packetlen);
|
packetbuf = gwbuf_clone_portion(readbuf, 0, packetlen);
|
||||||
@ -1541,3 +1534,213 @@ return_packetbuf:
|
|||||||
return packetbuf;
|
return packetbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move <npackets> from buffer pointed to by <*p_readbuf>.
|
||||||
|
*/
|
||||||
|
GWBUF* gw_MySQL_get_packets(
|
||||||
|
GWBUF** p_srcbuf,
|
||||||
|
int* npackets)
|
||||||
|
{
|
||||||
|
GWBUF* packetbuf;
|
||||||
|
GWBUF* targetbuf = NULL;
|
||||||
|
|
||||||
|
while (*npackets > 0 && (packetbuf = gw_MySQL_get_next_packet(p_srcbuf)) != NULL)
|
||||||
|
{
|
||||||
|
targetbuf = gwbuf_append(targetbuf, packetbuf);
|
||||||
|
*npackets -= 1;
|
||||||
|
}
|
||||||
|
ss_dassert(*npackets < 128);
|
||||||
|
ss_dassert(*npackets >= 0);
|
||||||
|
|
||||||
|
return targetbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If router expects to get separate, complete statements, add MySQL command
|
||||||
|
* to MySQLProtocol structure. It is removed when response has arrived.
|
||||||
|
*/
|
||||||
|
void protocol_add_srv_command(
|
||||||
|
MySQLProtocol* p,
|
||||||
|
mysql_server_cmd_t cmd)
|
||||||
|
{
|
||||||
|
spinlock_acquire(&p->protocol_lock);
|
||||||
|
|
||||||
|
if (p->protocol_command.cmd == MYSQL_COM_UNDEFINED)
|
||||||
|
{
|
||||||
|
p->protocol_command.cmd = cmd;
|
||||||
|
p->protocol_command.nresponse_packets = 0;
|
||||||
|
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Added command %s to fd %d.",
|
||||||
|
STRPACKETTYPE(cmd),
|
||||||
|
p->owner_dcb->fd)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
server_command_t* c =
|
||||||
|
(server_command_t *)malloc(sizeof(server_command_t));
|
||||||
|
c->cmd = cmd;
|
||||||
|
c->nresponse_packets = 0;
|
||||||
|
c->next = NULL;
|
||||||
|
|
||||||
|
p->protocol_command.next = c;
|
||||||
|
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Added another command %s to fd %d.",
|
||||||
|
STRPACKETTYPE(cmd),
|
||||||
|
p->owner_dcb->fd)));
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
c = &p->protocol_command;
|
||||||
|
|
||||||
|
while (c != NULL && c->cmd != MYSQL_COM_UNDEFINED)
|
||||||
|
{
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"fd %d : %d %s",
|
||||||
|
p->owner_dcb->fd,
|
||||||
|
c->cmd,
|
||||||
|
STRPACKETTYPE(c->cmd))));
|
||||||
|
c = c->next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
spinlock_release(&p->protocol_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If router processes separate statements, every stmt has corresponding MySQL
|
||||||
|
* command stored in MySQLProtocol structure.
|
||||||
|
*
|
||||||
|
* Remove current (=oldest) command.
|
||||||
|
*/
|
||||||
|
void protocol_remove_srv_command(
|
||||||
|
MySQLProtocol* p)
|
||||||
|
{
|
||||||
|
server_command_t* s;
|
||||||
|
spinlock_acquire(&p->protocol_lock);
|
||||||
|
s = &p->protocol_command;
|
||||||
|
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Removed command %s from fd %d.",
|
||||||
|
STRPACKETTYPE(s->cmd),
|
||||||
|
p->owner_dcb->fd)));
|
||||||
|
|
||||||
|
if (s->next == NULL)
|
||||||
|
{
|
||||||
|
p->protocol_command.cmd = MYSQL_COM_UNDEFINED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->protocol_command = *(s->next);
|
||||||
|
free(s->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_release(&p->protocol_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_server_cmd_t protocol_get_srv_command(
|
||||||
|
MySQLProtocol* p,
|
||||||
|
bool removep)
|
||||||
|
{
|
||||||
|
mysql_server_cmd_t cmd;
|
||||||
|
|
||||||
|
cmd = p->protocol_command.cmd;
|
||||||
|
|
||||||
|
if (removep)
|
||||||
|
{
|
||||||
|
protocol_remove_srv_command(p);
|
||||||
|
}
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Read command %s for fd %d.",
|
||||||
|
STRPACKETTYPE(cmd),
|
||||||
|
p->owner_dcb->fd)));
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return how many packets are included in the server's response.
|
||||||
|
*/
|
||||||
|
int get_stmt_nresponse_packets(
|
||||||
|
GWBUF* buf,
|
||||||
|
mysql_server_cmd_t cmd)
|
||||||
|
{
|
||||||
|
int npackets;
|
||||||
|
uint8_t* packet;
|
||||||
|
int nparam;
|
||||||
|
int nattr;
|
||||||
|
uint8_t* data;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case MYSQL_COM_STMT_PREPARE:
|
||||||
|
data = (uint8_t *)buf->start;
|
||||||
|
|
||||||
|
if (data[4] == 0xff)
|
||||||
|
{
|
||||||
|
npackets = 1; /*< error packet */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet = (uint8_t *)GWBUF_DATA(buf);
|
||||||
|
/** ok + nparam + eof + nattr + eof */
|
||||||
|
nparam = MYSQL_GET_STMTOK_NPARAM(packet);
|
||||||
|
nattr = MYSQL_GET_STMTOK_NATTR(packet);
|
||||||
|
|
||||||
|
npackets = 1 + nparam + MIN(1, nparam) +
|
||||||
|
nattr + MIN(nattr, 1);
|
||||||
|
ss_dassert(npackets<128);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
npackets = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ss_dassert(npackets<128);
|
||||||
|
return npackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
int protocol_get_nresponse_packets (
|
||||||
|
MySQLProtocol* p)
|
||||||
|
{
|
||||||
|
int rval;
|
||||||
|
|
||||||
|
CHK_PROTOCOL(p);
|
||||||
|
spinlock_acquire(&p->protocol_lock);
|
||||||
|
rval = p->protocol_command.nresponse_packets;
|
||||||
|
spinlock_release(&p->protocol_lock);
|
||||||
|
ss_dassert(rval<128);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool protocol_set_nresponse_packets (
|
||||||
|
MySQLProtocol* p,
|
||||||
|
int nresponse_packets)
|
||||||
|
{
|
||||||
|
bool succp;
|
||||||
|
|
||||||
|
CHK_PROTOCOL(p);
|
||||||
|
spinlock_acquire(&p->protocol_lock);
|
||||||
|
if (p->protocol_command.nresponse_packets > 0 &&
|
||||||
|
nresponse_packets > p->protocol_command.nresponse_packets)
|
||||||
|
{
|
||||||
|
succp = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->protocol_command.nresponse_packets = nresponse_packets;
|
||||||
|
ss_dassert(nresponse_packets<128);
|
||||||
|
succp = true;
|
||||||
|
}
|
||||||
|
spinlock_release(&p->protocol_lock);
|
||||||
|
|
||||||
|
return succp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ static void clientReply(
|
|||||||
static void handleError(
|
static void handleError(
|
||||||
ROUTER *instance,
|
ROUTER *instance,
|
||||||
void *router_session,
|
void *router_session,
|
||||||
char *message,
|
GWBUF *errbuf,
|
||||||
DCB *backend_dcb,
|
DCB *backend_dcb,
|
||||||
int action,
|
int action,
|
||||||
bool *succp);
|
bool *succp);
|
||||||
@ -708,7 +708,7 @@ static void
|
|||||||
handleError(
|
handleError(
|
||||||
ROUTER *instance,
|
ROUTER *instance,
|
||||||
void *router_session,
|
void *router_session,
|
||||||
char *message,
|
GWBUF *errbuf,
|
||||||
DCB *backend_dcb,
|
DCB *backend_dcb,
|
||||||
int action,
|
int action,
|
||||||
bool *succp)
|
bool *succp)
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <dcb.h>
|
#include <dcb.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
#include <modinfo.h>
|
#include <modinfo.h>
|
||||||
|
#include <mysql_client_server_protocol.h>
|
||||||
|
|
||||||
MODULE_INFO info = {
|
MODULE_INFO info = {
|
||||||
MODULE_API_ROUTER,
|
MODULE_API_ROUTER,
|
||||||
@ -97,6 +98,11 @@ static backend_ref_t* get_bref_from_dcb(ROUTER_CLIENT_SES* rses, DCB* dcb);
|
|||||||
|
|
||||||
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||||
|
|
||||||
|
#if defined(PREP_STMT_CACHING)
|
||||||
|
static prep_stmt_t* prep_stmt_init(prep_stmt_type_t type, void* id);
|
||||||
|
static void prep_stmt_done(prep_stmt_t* pstmt);
|
||||||
|
#endif /*< PREP_STMT_CACHING */
|
||||||
|
|
||||||
int bref_cmp_global_conn(
|
int bref_cmp_global_conn(
|
||||||
const void* bref1,
|
const void* bref1,
|
||||||
const void* bref2);
|
const void* bref2);
|
||||||
@ -207,8 +213,7 @@ static bool sescmd_cursor_next(
|
|||||||
static GWBUF* sescmd_cursor_process_replies(
|
static GWBUF* sescmd_cursor_process_replies(
|
||||||
DCB* client_dcb,
|
DCB* client_dcb,
|
||||||
GWBUF* replybuf,
|
GWBUF* replybuf,
|
||||||
sescmd_cursor_t* scur,
|
backend_ref_t* bref);
|
||||||
bool* has_query);
|
|
||||||
|
|
||||||
static void tracelog_routed_query(
|
static void tracelog_routed_query(
|
||||||
ROUTER_CLIENT_SES* rses,
|
ROUTER_CLIENT_SES* rses,
|
||||||
@ -229,8 +234,15 @@ static void refreshInstance(
|
|||||||
|
|
||||||
static void bref_clear_state(backend_ref_t* bref, bref_state_t state);
|
static void bref_clear_state(backend_ref_t* bref, bref_state_t state);
|
||||||
static void bref_set_state(backend_ref_t* bref, bref_state_t state);
|
static void bref_set_state(backend_ref_t* bref, bref_state_t state);
|
||||||
|
static sescmd_cursor_t* backend_ref_get_sescmd_cursor (backend_ref_t* bref);
|
||||||
|
|
||||||
static int router_handle_state_switch(DCB* dcb, DCB_REASON reason, void* data);
|
static int router_handle_state_switch(DCB* dcb, DCB_REASON reason, void* data);
|
||||||
|
static bool handle_error_new_connection(
|
||||||
|
ROUTER_INSTANCE* inst,
|
||||||
|
ROUTER_CLIENT_SES* rses,
|
||||||
|
DCB* backend_dcb,
|
||||||
|
GWBUF* errmsg);
|
||||||
|
static bool handle_error_reply_client(SESSION* ses, GWBUF* errmsg);
|
||||||
|
|
||||||
static SPINLOCK instlock;
|
static SPINLOCK instlock;
|
||||||
static ROUTER_INSTANCE* instances;
|
static ROUTER_INSTANCE* instances;
|
||||||
@ -482,8 +494,6 @@ static void* newSession(
|
|||||||
}
|
}
|
||||||
/** Copy config struct from router instance */
|
/** Copy config struct from router instance */
|
||||||
client_rses->rses_config = router->rwsplit_config;
|
client_rses->rses_config = router->rwsplit_config;
|
||||||
/** Create ID for the new client (router_client_ses) session */
|
|
||||||
client_rses->rses_id = router_client_ses_seq += 1;
|
|
||||||
|
|
||||||
spinlock_release(&router->lock);
|
spinlock_release(&router->lock);
|
||||||
/**
|
/**
|
||||||
@ -571,7 +581,6 @@ static void* newSession(
|
|||||||
backend_ref[i].bref_sescmd_cur.scmd_cur_chk_tail = CHK_NUM_SESCMD_CUR;
|
backend_ref[i].bref_sescmd_cur.scmd_cur_chk_tail = CHK_NUM_SESCMD_CUR;
|
||||||
#endif
|
#endif
|
||||||
backend_ref[i].bref_state = 0;
|
backend_ref[i].bref_state = 0;
|
||||||
bref_set_state(&backend_ref[i], BREF_NOT_USED);
|
|
||||||
backend_ref[i].bref_backend = router->servers[i];
|
backend_ref[i].bref_backend = router->servers[i];
|
||||||
/** store pointers to sescmd list to both cursors */
|
/** store pointers to sescmd list to both cursors */
|
||||||
backend_ref[i].bref_sescmd_cur.scmd_cur_rses = client_rses;
|
backend_ref[i].bref_sescmd_cur.scmd_cur_rses = client_rses;
|
||||||
@ -814,6 +823,7 @@ static bool get_dcb(
|
|||||||
*p_dcb = backend_ref[i].bref_dcb;
|
*p_dcb = backend_ref[i].bref_dcb;
|
||||||
smallest_nconn = b->backend_conn_count;
|
smallest_nconn = b->backend_conn_count;
|
||||||
succp = true;
|
succp = true;
|
||||||
|
ss_dassert(backend_ref[i].bref_dcb->state != DCB_STATE_ZOMBIE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,6 +835,7 @@ static bool get_dcb(
|
|||||||
{
|
{
|
||||||
*p_dcb = backend_ref->bref_dcb;
|
*p_dcb = backend_ref->bref_dcb;
|
||||||
succp = true;
|
succp = true;
|
||||||
|
ss_dassert(backend_ref->bref_dcb->state != DCB_STATE_ZOMBIE);
|
||||||
|
|
||||||
ss_dassert(
|
ss_dassert(
|
||||||
SERVER_IS_MASTER(backend_ref->bref_backend->backend_server) &&
|
SERVER_IS_MASTER(backend_ref->bref_backend->backend_server) &&
|
||||||
@ -892,7 +903,7 @@ static int routeQuery(
|
|||||||
GWBUF* plainsqlbuf = NULL;
|
GWBUF* plainsqlbuf = NULL;
|
||||||
char* querystr = NULL;
|
char* querystr = NULL;
|
||||||
char* startpos;
|
char* startpos;
|
||||||
unsigned char packet_type;
|
mysql_server_cmd_t packet_type;
|
||||||
uint8_t* packet;
|
uint8_t* packet;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
DCB* master_dcb = NULL;
|
DCB* master_dcb = NULL;
|
||||||
@ -901,6 +912,7 @@ static int routeQuery(
|
|||||||
ROUTER_CLIENT_SES* router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
|
ROUTER_CLIENT_SES* router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
|
||||||
bool rses_is_closed = false;
|
bool rses_is_closed = false;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
MYSQL* mysql = NULL;
|
||||||
|
|
||||||
CHK_CLIENT_RSES(router_cli_ses);
|
CHK_CLIENT_RSES(router_cli_ses);
|
||||||
|
|
||||||
@ -915,10 +927,10 @@ static int routeQuery(
|
|||||||
if (rses_is_closed)
|
if (rses_is_closed)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* COM_QUIT may have sent by client and as a part of backend
|
* MYSQL_COM_QUIT may have sent by client and as a part of backend
|
||||||
* closing procedure.
|
* closing procedure.
|
||||||
*/
|
*/
|
||||||
if (packet_type != COM_QUIT)
|
if (packet_type != MYSQL_COM_QUIT)
|
||||||
{
|
{
|
||||||
LOGIF(LE,
|
LOGIF(LE,
|
||||||
(skygw_log_write_flush(
|
(skygw_log_write_flush(
|
||||||
@ -941,21 +953,24 @@ static int routeQuery(
|
|||||||
CHK_DCB(master_dcb);
|
CHK_DCB(master_dcb);
|
||||||
|
|
||||||
switch(packet_type) {
|
switch(packet_type) {
|
||||||
case COM_QUIT: /**< 1 QUIT will close all sessions */
|
case MYSQL_COM_QUIT: /*< 1 QUIT will close all sessions */
|
||||||
case COM_INIT_DB: /**< 2 DDL must go to the master */
|
case MYSQL_COM_INIT_DB: /*< 2 DDL must go to the master */
|
||||||
case COM_REFRESH: /**< 7 - I guess this is session but not sure */
|
case MYSQL_COM_REFRESH: /*< 7 - I guess this is session but not sure */
|
||||||
case COM_DEBUG: /**< 0d all servers dump debug info to stdout */
|
case MYSQL_COM_DEBUG: /*< 0d all servers dump debug info to stdout */
|
||||||
case COM_PING: /**< 0e all servers are pinged */
|
case MYSQL_COM_PING: /*< 0e all servers are pinged */
|
||||||
case COM_CHANGE_USER: /**< 11 all servers change it accordingly */
|
case MYSQL_COM_CHANGE_USER: /*< 11 all servers change it accordingly */
|
||||||
|
case MYSQL_COM_STMT_CLOSE: /*< free prepared statement */
|
||||||
|
case MYSQL_COM_STMT_SEND_LONG_DATA: /*< send data to column */
|
||||||
|
case MYSQL_COM_STMT_RESET: /*< resets the data of a prepared statement */
|
||||||
qtype = QUERY_TYPE_SESSION_WRITE;
|
qtype = QUERY_TYPE_SESSION_WRITE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COM_CREATE_DB: /**< 5 DDL must go to the master */
|
case MYSQL_COM_CREATE_DB: /**< 5 DDL must go to the master */
|
||||||
case COM_DROP_DB: /**< 6 DDL must go to the master */
|
case MYSQL_COM_DROP_DB: /**< 6 DDL must go to the master */
|
||||||
qtype = QUERY_TYPE_WRITE;
|
qtype = QUERY_TYPE_WRITE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COM_QUERY:
|
case MYSQL_COM_QUERY:
|
||||||
plainsqlbuf = gwbuf_clone_transform(querybuf,
|
plainsqlbuf = gwbuf_clone_transform(querybuf,
|
||||||
GWBUF_TYPE_PLAINSQL);
|
GWBUF_TYPE_PLAINSQL);
|
||||||
len = GWBUF_LENGTH(plainsqlbuf);
|
len = GWBUF_LENGTH(plainsqlbuf);
|
||||||
@ -963,24 +978,45 @@ static int routeQuery(
|
|||||||
querystr = (char *)malloc(len+1);
|
querystr = (char *)malloc(len+1);
|
||||||
memcpy(querystr, startpos, len);
|
memcpy(querystr, startpos, len);
|
||||||
memset(&querystr[len], 0, 1);
|
memset(&querystr[len], 0, 1);
|
||||||
// querystr = (char *)GWBUF_DATA(plainsqlbuf);
|
/**
|
||||||
/*
|
* Use mysql handle to query information from parse tree.
|
||||||
* querystr = master_dcb->func.getquerystr(
|
* call skygw_query_classifier_free before exit!
|
||||||
* (void *) gwbuf_clone(querybuf),
|
|
||||||
* &querystr_is_copy);
|
|
||||||
*/
|
*/
|
||||||
|
qtype = skygw_query_classifier_get_type(querystr, 0, &mysql);
|
||||||
qtype = skygw_query_classifier_get_type(querystr, 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COM_SHUTDOWN: /**< 8 where should shutdown be routed ? */
|
case MYSQL_COM_STMT_PREPARE:
|
||||||
case COM_STATISTICS: /**< 9 ? */
|
plainsqlbuf = gwbuf_clone_transform(querybuf,
|
||||||
case COM_PROCESS_INFO: /**< 0a ? */
|
GWBUF_TYPE_PLAINSQL);
|
||||||
case COM_CONNECT: /**< 0b ? */
|
len = GWBUF_LENGTH(plainsqlbuf);
|
||||||
case COM_PROCESS_KILL: /**< 0c ? */
|
/** unnecessary if buffer includes additional terminating null */
|
||||||
case COM_TIME: /**< 0f should this be run in gateway ? */
|
querystr = (char *)malloc(len+1);
|
||||||
case COM_DELAYED_INSERT: /**< 10 ? */
|
memcpy(querystr, startpos, len);
|
||||||
case COM_DAEMON: /**< 1d ? */
|
memset(&querystr[len], 0, 1);
|
||||||
|
qtype = skygw_query_classifier_get_type(querystr, 0, &mysql);
|
||||||
|
qtype |= QUERY_TYPE_PREPARE_STMT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MYSQL_COM_STMT_EXECUTE:
|
||||||
|
plainsqlbuf = gwbuf_clone_transform(querybuf,
|
||||||
|
GWBUF_TYPE_PLAINSQL);
|
||||||
|
len = GWBUF_LENGTH(plainsqlbuf);
|
||||||
|
/** unnecessary if buffer includes additional terminating null */
|
||||||
|
querystr = (char *)malloc(len+1);
|
||||||
|
memcpy(querystr, startpos, len);
|
||||||
|
memset(&querystr[len], 0, 1);
|
||||||
|
qtype = skygw_query_classifier_get_type(querystr, 0, &mysql);
|
||||||
|
qtype |= QUERY_TYPE_EXEC_STMT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MYSQL_COM_SHUTDOWN: /**< 8 where should shutdown be routed ? */
|
||||||
|
case MYSQL_COM_STATISTICS: /**< 9 ? */
|
||||||
|
case MYSQL_COM_PROCESS_INFO: /**< 0a ? */
|
||||||
|
case MYSQL_COM_CONNECT: /**< 0b ? */
|
||||||
|
case MYSQL_COM_PROCESS_KILL: /**< 0c ? */
|
||||||
|
case MYSQL_COM_TIME: /**< 0f should this be run in gateway ? */
|
||||||
|
case MYSQL_COM_DELAYED_INSERT: /**< 10 ? */
|
||||||
|
case MYSQL_COM_DAEMON: /**< 1d ? */
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
} /**< switch by packet type */
|
} /**< switch by packet type */
|
||||||
@ -1024,11 +1060,13 @@ static int routeQuery(
|
|||||||
/**
|
/**
|
||||||
* Session update is always routed in the same way.
|
* Session update is always routed in the same way.
|
||||||
*/
|
*/
|
||||||
if (QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE))
|
if (QUERY_IS_TYPE(qtype, QUERY_TYPE_SESSION_WRITE) ||
|
||||||
|
QUERY_IS_TYPE(qtype, QUERY_TYPE_PREPARE_STMT) ||
|
||||||
|
QUERY_IS_TYPE(qtype, QUERY_TYPE_PREPARE_NAMED_STMT))
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* It is not sure if the session command in question requires
|
* It is not sure if the session command in question requires
|
||||||
* response. Statement must be examined in route_session_write.
|
* response. Statement is examined in route_session_write.
|
||||||
*/
|
*/
|
||||||
bool succp = route_session_write(
|
bool succp = route_session_write(
|
||||||
router_cli_ses,
|
router_cli_ses,
|
||||||
@ -1050,9 +1088,8 @@ static int routeQuery(
|
|||||||
|
|
||||||
LOGIF(LT, (skygw_log_write(
|
LOGIF(LT, (skygw_log_write(
|
||||||
LOGFILE_TRACE,
|
LOGFILE_TRACE,
|
||||||
"[%s.%d]\tRead-only query, routing to Slave.",
|
"[%s]\tRead-only query, routing to Slave.",
|
||||||
inst->service->name,
|
inst->service->name)));
|
||||||
router_cli_ses->rses_id)));
|
|
||||||
ss_dassert(QUERY_IS_TYPE(qtype, QUERY_TYPE_READ));
|
ss_dassert(QUERY_IS_TYPE(qtype, QUERY_TYPE_READ));
|
||||||
|
|
||||||
/** Lock router session */
|
/** Lock router session */
|
||||||
@ -1060,7 +1097,6 @@ static int routeQuery(
|
|||||||
{
|
{
|
||||||
goto return_ret;
|
goto return_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
succp = get_dcb(&slave_dcb, router_cli_ses, BE_SLAVE);
|
succp = get_dcb(&slave_dcb, router_cli_ses, BE_SLAVE);
|
||||||
|
|
||||||
if (succp)
|
if (succp)
|
||||||
@ -1152,6 +1188,10 @@ return_ret:
|
|||||||
{
|
{
|
||||||
free(querystr);
|
free(querystr);
|
||||||
}
|
}
|
||||||
|
if (mysql != NULL)
|
||||||
|
{
|
||||||
|
skygw_query_classifier_free(mysql);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,8 +1319,7 @@ static void clientReply(
|
|||||||
DCB* client_dcb;
|
DCB* client_dcb;
|
||||||
ROUTER_CLIENT_SES* router_cli_ses;
|
ROUTER_CLIENT_SES* router_cli_ses;
|
||||||
sescmd_cursor_t* scur = NULL;
|
sescmd_cursor_t* scur = NULL;
|
||||||
backend_ref_t* backend_ref;
|
backend_ref_t* bref;
|
||||||
int i;
|
|
||||||
|
|
||||||
router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
|
router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
|
||||||
CHK_CLIENT_RSES(router_cli_ses);
|
CHK_CLIENT_RSES(router_cli_ses);
|
||||||
@ -1323,23 +1362,10 @@ static void clientReply(
|
|||||||
/** Log to debug that router was closed */
|
/** Log to debug that router was closed */
|
||||||
goto lock_failed;
|
goto lock_failed;
|
||||||
}
|
}
|
||||||
backend_ref = router_cli_ses->rses_backend_ref;
|
bref = get_bref_from_dcb(router_cli_ses, backend_dcb);
|
||||||
|
|
||||||
/** find backend_dcb's corresponding BACKEND */
|
CHK_BACKEND_REF(bref);
|
||||||
i = 0;
|
scur = &bref->bref_sescmd_cur;
|
||||||
while (i<router_cli_ses->rses_nbackends &&
|
|
||||||
backend_ref[i].bref_dcb != backend_dcb)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
ss_dassert(backend_ref[i].bref_dcb == backend_dcb);
|
|
||||||
|
|
||||||
LOGIF(LT, tracelog_routed_query(router_cli_ses,
|
|
||||||
"reply_by_statement",
|
|
||||||
&backend_ref[i],
|
|
||||||
gwbuf_clone(writebuf)));
|
|
||||||
|
|
||||||
scur = &backend_ref[i].bref_sescmd_cur;
|
|
||||||
/**
|
/**
|
||||||
* Active cursor means that reply is from session command
|
* Active cursor means that reply is from session command
|
||||||
* execution. Majority of the time there are no session commands
|
* execution. Majority of the time there are no session commands
|
||||||
@ -1347,34 +1373,76 @@ static void clientReply(
|
|||||||
*/
|
*/
|
||||||
if (sescmd_cursor_is_active(scur))
|
if (sescmd_cursor_is_active(scur))
|
||||||
{
|
{
|
||||||
bool has_query;
|
if (MYSQL_IS_ERROR_PACKET(((uint8_t *)GWBUF_DATA(writebuf))))
|
||||||
writebuf = sescmd_cursor_process_replies(client_dcb,
|
|
||||||
writebuf,
|
|
||||||
scur,
|
|
||||||
&has_query);
|
|
||||||
if (has_query)
|
|
||||||
{
|
{
|
||||||
bref_clear_state(backend_ref, BREF_WAITING_RESULT);
|
SESSION* ses = backend_dcb->session;
|
||||||
}
|
uint8_t* buf =
|
||||||
}
|
(uint8_t *)GWBUF_DATA((scur->scmd_cur_cmd->my_sescmd_buf));
|
||||||
|
size_t len = MYSQL_GET_PACKET_LEN(buf);
|
||||||
|
char* cmdstr = (char *)malloc(len+1);
|
||||||
|
ROUTER_INSTANCE* inst = (ROUTER_INSTANCE *)instance;
|
||||||
|
|
||||||
|
snprintf(cmdstr, len+1, "%s", &buf[5]);
|
||||||
|
|
||||||
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
|
LOGFILE_ERROR,
|
||||||
|
"Error : Failed to execute %s in %s:%d.",
|
||||||
|
cmdstr,
|
||||||
|
bref->bref_backend->backend_server->name,
|
||||||
|
bref->bref_backend->backend_server->port)));
|
||||||
|
|
||||||
|
free(cmdstr);
|
||||||
|
/** Inform the client */
|
||||||
|
handle_error_reply_client(ses,writebuf);
|
||||||
|
|
||||||
/** Unlock router session */
|
/** Unlock router session */
|
||||||
rses_end_locked_router_action(router_cli_ses);
|
rses_end_locked_router_action(router_cli_ses);
|
||||||
|
goto lock_failed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Discard all those responses that have already been sent to
|
||||||
|
* the client. Return with buffer including response that
|
||||||
|
* needs to be sent to client or NULL.
|
||||||
|
*/
|
||||||
|
writebuf = sescmd_cursor_process_replies(client_dcb,
|
||||||
|
writebuf,
|
||||||
|
bref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (writebuf != NULL && client_dcb != NULL)
|
if (writebuf != NULL && client_dcb != NULL)
|
||||||
{
|
{
|
||||||
/** Write reply to client DCB */
|
/** Write reply to client DCB */
|
||||||
SESSION_ROUTE_REPLY(backend_dcb->session, writebuf);
|
SESSION_ROUTE_REPLY(backend_dcb->session, writebuf);
|
||||||
|
bref_clear_state(bref, BREF_WAITING_RESULT);
|
||||||
LOGIF(LT, (skygw_log_write_flush(
|
|
||||||
LOGFILE_TRACE,
|
|
||||||
"%lu [clientReply:rwsplit] client dcb %p, "
|
|
||||||
"backend dcb %p. End of normal reply.",
|
|
||||||
pthread_self(),
|
|
||||||
client_dcb,
|
|
||||||
backend_dcb)));
|
|
||||||
bref_clear_state(backend_ref, BREF_WAITING_RESULT);
|
|
||||||
}
|
}
|
||||||
|
/** Unlock router session */
|
||||||
|
rses_end_locked_router_action(router_cli_ses);
|
||||||
|
|
||||||
|
/** Lock router session */
|
||||||
|
if (!rses_begin_locked_router_action(router_cli_ses))
|
||||||
|
{
|
||||||
|
/** Log to debug that router was closed */
|
||||||
|
goto lock_failed;
|
||||||
|
}
|
||||||
|
/** There is one pending session command to be xexecuted. */
|
||||||
|
if (sescmd_cursor_is_active(scur))
|
||||||
|
{
|
||||||
|
bool succp;
|
||||||
|
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Backend %s:%d processed reply and starts to execute "
|
||||||
|
"active cursor.",
|
||||||
|
bref->bref_backend->backend_server->name,
|
||||||
|
bref->bref_backend->backend_server->port)));
|
||||||
|
|
||||||
|
succp = execute_sescmd_in_backend(bref);
|
||||||
|
}
|
||||||
|
/** Unlock router session */
|
||||||
|
rses_end_locked_router_action(router_cli_ses);
|
||||||
|
|
||||||
lock_failed:
|
lock_failed:
|
||||||
return;
|
return;
|
||||||
@ -1423,6 +1491,13 @@ static void bref_set_state(
|
|||||||
bref_state_t state)
|
bref_state_t state)
|
||||||
{
|
{
|
||||||
bref->bref_state |= state;
|
bref->bref_state |= state;
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Set state %d for %s:%d fd %d",
|
||||||
|
bref->bref_state,
|
||||||
|
bref->bref_backend->backend_server->name,
|
||||||
|
bref->bref_backend->backend_server->port,
|
||||||
|
bref->bref_dcb->fd)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1603,7 +1678,7 @@ static bool select_connect_backend_servers(
|
|||||||
{
|
{
|
||||||
BACKEND* b = backend_ref[i].bref_backend;
|
BACKEND* b = backend_ref[i].bref_backend;
|
||||||
|
|
||||||
LOGIF(LT, (skygw_log_write(
|
LOGIF(LT, (skygw_log_write_flush(
|
||||||
LOGFILE_TRACE,
|
LOGFILE_TRACE,
|
||||||
"Examine server "
|
"Examine server "
|
||||||
"%s:%d %s with %d connections. "
|
"%s:%d %s with %d connections. "
|
||||||
@ -1645,18 +1720,15 @@ static bool select_connect_backend_servers(
|
|||||||
*/
|
*/
|
||||||
execute_sescmd_history(&backend_ref[i]);
|
execute_sescmd_history(&backend_ref[i]);
|
||||||
/**
|
/**
|
||||||
* Callback which is called when
|
* When server fails, this callback
|
||||||
* node fails.
|
* is called.
|
||||||
*/
|
*/
|
||||||
dcb_add_callback(
|
dcb_add_callback(
|
||||||
backend_ref[i].bref_dcb,
|
backend_ref[i].bref_dcb,
|
||||||
DCB_REASON_NOT_RESPONDING,
|
DCB_REASON_NOT_RESPONDING,
|
||||||
&router_handle_state_switch,
|
&router_handle_state_switch,
|
||||||
(void *)&backend_ref[i]);
|
(void *)&backend_ref[i]);
|
||||||
bref_clear_state(&backend_ref[i],
|
backend_ref[i].bref_state = 0;
|
||||||
BREF_CLOSED);
|
|
||||||
bref_clear_state(&backend_ref[i],
|
|
||||||
BREF_NOT_USED);
|
|
||||||
bref_set_state(&backend_ref[i],
|
bref_set_state(&backend_ref[i],
|
||||||
BREF_IN_USE);
|
BREF_IN_USE);
|
||||||
/**
|
/**
|
||||||
@ -1698,20 +1770,20 @@ static bool select_connect_backend_servers(
|
|||||||
if (backend_ref[i].bref_dcb != NULL)
|
if (backend_ref[i].bref_dcb != NULL)
|
||||||
{
|
{
|
||||||
master_connected = true;
|
master_connected = true;
|
||||||
|
/**
|
||||||
|
* When server fails, this callback
|
||||||
|
* is called.
|
||||||
|
*/
|
||||||
dcb_add_callback(
|
dcb_add_callback(
|
||||||
backend_ref[i].bref_dcb,
|
backend_ref[i].bref_dcb,
|
||||||
DCB_REASON_NOT_RESPONDING,
|
DCB_REASON_NOT_RESPONDING,
|
||||||
&router_handle_state_switch,
|
&router_handle_state_switch,
|
||||||
(void *)&backend_ref[i]);
|
(void *)&backend_ref[i]);
|
||||||
|
|
||||||
bref_clear_state(&backend_ref[i],
|
backend_ref[i].bref_state = 0;
|
||||||
BREF_NOT_USED);
|
|
||||||
bref_set_state(&backend_ref[i],
|
bref_set_state(&backend_ref[i],
|
||||||
BREF_IN_USE);
|
BREF_IN_USE);
|
||||||
|
/** Increase backend connection counters */
|
||||||
/** Increase backend connection counter */
|
|
||||||
/** Increase backend connection counter */
|
|
||||||
atomic_add(&b->backend_server->stats.n_current, 1);
|
atomic_add(&b->backend_server->stats.n_current, 1);
|
||||||
atomic_add(&b->backend_server->stats.n_connections, 1);
|
atomic_add(&b->backend_server->stats.n_connections, 1);
|
||||||
atomic_add(&b->backend_conn_count, 1);
|
atomic_add(&b->backend_conn_count, 1);
|
||||||
@ -1725,7 +1797,7 @@ static bool select_connect_backend_servers(
|
|||||||
"connection with master %s:%d",
|
"connection with master %s:%d",
|
||||||
b->backend_server->name,
|
b->backend_server->name,
|
||||||
b->backend_server->port)));
|
b->backend_server->port)));
|
||||||
/* handle connect error */
|
/** handle connect error */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1905,8 +1977,7 @@ static bool select_connect_backend_servers(
|
|||||||
/** disconnect opened connections */
|
/** disconnect opened connections */
|
||||||
dcb_close(backend_ref[i].bref_dcb);
|
dcb_close(backend_ref[i].bref_dcb);
|
||||||
bref_clear_state(&backend_ref[i], BREF_IN_USE);
|
bref_clear_state(&backend_ref[i], BREF_IN_USE);
|
||||||
bref_set_state(&backend_ref[i], BREF_NOT_USED);
|
/** Decrease backend's connection counter. */
|
||||||
|
|
||||||
atomic_add(&backend_ref[i].bref_backend->backend_conn_count, -1);
|
atomic_add(&backend_ref[i].bref_backend->backend_conn_count, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1956,7 +2027,7 @@ static void rses_property_done(
|
|||||||
mysql_sescmd_done(&prop->rses_prop_data.sescmd);
|
mysql_sescmd_done(&prop->rses_prop_data.sescmd);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGIF(LD, (skygw_log_write_flush(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [rses_property_done] Unknown property type %d "
|
"%lu [rses_property_done] Unknown property type %d "
|
||||||
"in property %p",
|
"in property %p",
|
||||||
@ -2100,16 +2171,16 @@ static void mysql_sescmd_done(
|
|||||||
static GWBUF* sescmd_cursor_process_replies(
|
static GWBUF* sescmd_cursor_process_replies(
|
||||||
DCB* client_dcb,
|
DCB* client_dcb,
|
||||||
GWBUF* replybuf,
|
GWBUF* replybuf,
|
||||||
sescmd_cursor_t* scur,
|
backend_ref_t* bref)
|
||||||
bool* has_query)
|
|
||||||
{
|
{
|
||||||
const size_t headerlen = 4; /*< mysql packet header */
|
const size_t headerlen = 4; /*< mysql packet header */
|
||||||
uint8_t* packet;
|
|
||||||
size_t packetlen;
|
size_t packetlen;
|
||||||
|
uint8_t* packet;
|
||||||
mysql_sescmd_t* scmd;
|
mysql_sescmd_t* scmd;
|
||||||
|
sescmd_cursor_t* scur;
|
||||||
|
|
||||||
|
scur = &bref->bref_sescmd_cur;
|
||||||
ss_dassert(SPINLOCK_IS_LOCKED(&(scur->scmd_cur_rses->rses_lock)));
|
ss_dassert(SPINLOCK_IS_LOCKED(&(scur->scmd_cur_rses->rses_lock)));
|
||||||
|
|
||||||
scmd = sescmd_cursor_get_command(scur);
|
scmd = sescmd_cursor_get_command(scur);
|
||||||
|
|
||||||
CHK_DCB(client_dcb);
|
CHK_DCB(client_dcb);
|
||||||
@ -2121,18 +2192,41 @@ static GWBUF* sescmd_cursor_process_replies(
|
|||||||
*/
|
*/
|
||||||
while (scmd != NULL && replybuf != NULL)
|
while (scmd != NULL && replybuf != NULL)
|
||||||
{
|
{
|
||||||
|
/** Faster backend has already responded to client : discard */
|
||||||
if (scmd->my_sescmd_is_replied)
|
if (scmd->my_sescmd_is_replied)
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Discard heading packets if their related command is
|
|
||||||
* already replied.
|
|
||||||
*/
|
|
||||||
CHK_GWBUF(replybuf);
|
CHK_GWBUF(replybuf);
|
||||||
packet = (uint8_t *)GWBUF_DATA(replybuf);
|
packet = (uint8_t *)GWBUF_DATA(replybuf);
|
||||||
|
/**
|
||||||
|
* If it is response to MYSQL_COM_STMT_PREPARE, then buffer
|
||||||
|
* only includes the response.
|
||||||
|
*/
|
||||||
|
if (scmd->my_sescmd_prop->rses_prop_data.sescmd.my_sescmd_packet_type ==
|
||||||
|
MYSQL_COM_STMT_PREPARE)
|
||||||
|
{
|
||||||
|
while (replybuf != NULL)
|
||||||
|
{
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
int buflen;
|
||||||
|
|
||||||
|
buflen = GWBUF_LENGTH(replybuf);
|
||||||
|
replybuf = gwbuf_consume(replybuf, buflen);
|
||||||
|
#else
|
||||||
|
replybuf = gwbuf_consume(
|
||||||
|
replybuf,
|
||||||
|
GWBUF_LENGTH(replybuf));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Only consume the leading packet */
|
||||||
|
else
|
||||||
|
{
|
||||||
packetlen = packet[0]+packet[1]*256+packet[2]*256*256;
|
packetlen = packet[0]+packet[1]*256+packet[2]*256*256;
|
||||||
replybuf = gwbuf_consume(replybuf, packetlen+headerlen);
|
replybuf = gwbuf_consume(replybuf, packetlen+headerlen);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
/** Response is in the buffer and it will be sent to client. */
|
||||||
|
else if (replybuf != NULL)
|
||||||
{
|
{
|
||||||
/** Mark the rest session commands as replied */
|
/** Mark the rest session commands as replied */
|
||||||
scmd->my_sescmd_is_replied = true;
|
scmd->my_sescmd_is_replied = true;
|
||||||
@ -2149,8 +2243,6 @@ static GWBUF* sescmd_cursor_process_replies(
|
|||||||
scur->scmd_cur_active = false;
|
scur->scmd_cur_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** vraa:this is set but only because there's not yet way to find out */
|
|
||||||
*has_query = false;
|
|
||||||
ss_dassert(replybuf == NULL || *scur->scmd_cur_ptr_property == NULL);
|
ss_dassert(replybuf == NULL || *scur->scmd_cur_ptr_property == NULL);
|
||||||
|
|
||||||
return replybuf;
|
return replybuf;
|
||||||
@ -2287,12 +2379,13 @@ static bool execute_sescmd_in_backend(
|
|||||||
backend_ref_t* backend_ref)
|
backend_ref_t* backend_ref)
|
||||||
{
|
{
|
||||||
DCB* dcb;
|
DCB* dcb;
|
||||||
bool succp = true;
|
bool succp;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
sescmd_cursor_t* scur;
|
sescmd_cursor_t* scur;
|
||||||
|
|
||||||
if (BREF_IS_CLOSED(backend_ref))
|
if (BREF_IS_CLOSED(backend_ref))
|
||||||
{
|
{
|
||||||
|
succp = false;
|
||||||
goto return_succp;
|
goto return_succp;
|
||||||
}
|
}
|
||||||
dcb = backend_ref->bref_dcb;
|
dcb = backend_ref->bref_dcb;
|
||||||
@ -2309,6 +2402,10 @@ static bool execute_sescmd_in_backend(
|
|||||||
if (sescmd_cursor_get_command(scur) == NULL)
|
if (sescmd_cursor_get_command(scur) == NULL)
|
||||||
{
|
{
|
||||||
succp = false;
|
succp = false;
|
||||||
|
LOGIF(LT, (skygw_log_write_flush(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Cursor had no pending session commands.")));
|
||||||
|
|
||||||
goto return_succp;
|
goto return_succp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2317,14 +2414,26 @@ static bool execute_sescmd_in_backend(
|
|||||||
/** Cursor is left active when function returns. */
|
/** Cursor is left active when function returns. */
|
||||||
sescmd_cursor_set_active(scur, true);
|
sescmd_cursor_set_active(scur, true);
|
||||||
}
|
}
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
LOGIF(LT, tracelog_routed_query(scur->scmd_cur_rses,
|
LOGIF(LT, tracelog_routed_query(scur->scmd_cur_rses,
|
||||||
"execute_sescmd_in_backend",
|
"execute_sescmd_in_backend",
|
||||||
backend_ref,
|
backend_ref,
|
||||||
sescmd_cursor_clone_querybuf(scur)));
|
sescmd_cursor_clone_querybuf(scur)));
|
||||||
|
|
||||||
|
{
|
||||||
|
GWBUF* tmpbuf = sescmd_cursor_clone_querybuf(scur);
|
||||||
|
uint8_t* ptr = GWBUF_DATA(tmpbuf);
|
||||||
|
unsigned char cmd = MYSQL_GET_COMMAND(ptr);
|
||||||
|
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Just before write, fd %d : cmd %s.",
|
||||||
|
dcb->fd,
|
||||||
|
STRPACKETTYPE(cmd))));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
switch (scur->scmd_cur_cmd->my_sescmd_packet_type) {
|
switch (scur->scmd_cur_cmd->my_sescmd_packet_type) {
|
||||||
case COM_CHANGE_USER:
|
case MYSQL_COM_CHANGE_USER:
|
||||||
rc = dcb->func.auth(
|
rc = dcb->func.auth(
|
||||||
dcb,
|
dcb,
|
||||||
NULL,
|
NULL,
|
||||||
@ -2332,8 +2441,8 @@ static bool execute_sescmd_in_backend(
|
|||||||
sescmd_cursor_clone_querybuf(scur));
|
sescmd_cursor_clone_querybuf(scur));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COM_QUERY:
|
case MYSQL_COM_QUERY:
|
||||||
case COM_INIT_DB:
|
case MYSQL_COM_INIT_DB:
|
||||||
default:
|
default:
|
||||||
rc = dcb->func.write(
|
rc = dcb->func.write(
|
||||||
dcb,
|
dcb,
|
||||||
@ -2349,10 +2458,7 @@ static bool execute_sescmd_in_backend(
|
|||||||
|
|
||||||
if (rc == 1)
|
if (rc == 1)
|
||||||
{
|
{
|
||||||
/**
|
succp = true;
|
||||||
* All but COM_QUIT cause backend to send reply. flag backend_ref.
|
|
||||||
*/
|
|
||||||
bref_set_state(backend_ref, BREF_WAITING_RESULT);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2464,7 +2570,7 @@ static void tracelog_routed_query(
|
|||||||
|
|
||||||
be_type = BACKEND_TYPE(b);
|
be_type = BACKEND_TYPE(b);
|
||||||
|
|
||||||
if (GWBUF_TYPE(buf) == GWBUF_TYPE_MYSQL)
|
if (GWBUF_IS_TYPE_MYSQL(buf))
|
||||||
{
|
{
|
||||||
len = packet[0];
|
len = packet[0];
|
||||||
len += 256*packet[1];
|
len += 256*packet[1];
|
||||||
@ -2488,6 +2594,28 @@ static void tracelog_routed_query(
|
|||||||
dcb)));
|
dcb)));
|
||||||
free(querystr);
|
free(querystr);
|
||||||
}
|
}
|
||||||
|
else if (packet_type == '\x22' ||
|
||||||
|
packet_type == 0x22 ||
|
||||||
|
packet_type == '\x26' ||
|
||||||
|
packet_type == 0x26 ||
|
||||||
|
true)
|
||||||
|
{
|
||||||
|
querystr = (char *)malloc(len);
|
||||||
|
memcpy(querystr, startpos, len-1);
|
||||||
|
querystr[len-1] = '\0';
|
||||||
|
LOGIF(LT, (skygw_log_write_flush(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"%lu [%s] %d bytes long buf, \"%s\" -> %s:%d %s dcb %p",
|
||||||
|
pthread_self(),
|
||||||
|
funcname,
|
||||||
|
buflen,
|
||||||
|
querystr,
|
||||||
|
b->backend_server->name,
|
||||||
|
b->backend_server->port,
|
||||||
|
STRBETYPE(be_type),
|
||||||
|
dcb)));
|
||||||
|
free(querystr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gwbuf_free(buf);
|
gwbuf_free(buf);
|
||||||
}
|
}
|
||||||
@ -2551,12 +2679,14 @@ static bool route_session_write(
|
|||||||
backend_ref = router_cli_ses->rses_backend_ref;
|
backend_ref = router_cli_ses->rses_backend_ref;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* COM_QUIT is one-way message. Server doesn't respond to that.
|
* These are one-way messages and server doesn't respond to them.
|
||||||
* Therefore reply processing is unnecessary and session
|
* Therefore reply processing is unnecessary and session
|
||||||
* command property is not needed. It is just routed to both
|
* command property is not needed. It is just routed to all available
|
||||||
* backends.
|
* backends.
|
||||||
*/
|
*/
|
||||||
if (packet_type == COM_QUIT)
|
if (packet_type == MYSQL_COM_STMT_SEND_LONG_DATA ||
|
||||||
|
packet_type == MYSQL_COM_QUIT ||
|
||||||
|
packet_type == MYSQL_COM_STMT_CLOSE)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -2587,6 +2717,14 @@ static bool route_session_write(
|
|||||||
gwbuf_free(querybuf);
|
gwbuf_free(querybuf);
|
||||||
goto return_succp;
|
goto return_succp;
|
||||||
}
|
}
|
||||||
|
/** Lock router session */
|
||||||
|
if (!rses_begin_locked_router_action(router_cli_ses))
|
||||||
|
{
|
||||||
|
rses_property_done(prop);
|
||||||
|
succp = false;
|
||||||
|
goto return_succp;
|
||||||
|
}
|
||||||
|
|
||||||
prop = rses_property_init(RSES_PROP_TYPE_SESCMD);
|
prop = rses_property_init(RSES_PROP_TYPE_SESCMD);
|
||||||
/**
|
/**
|
||||||
* Additional reference is created to querybuf to
|
* Additional reference is created to querybuf to
|
||||||
@ -2595,19 +2733,40 @@ static bool route_session_write(
|
|||||||
*/
|
*/
|
||||||
mysql_sescmd_init(prop, querybuf, packet_type, router_cli_ses);
|
mysql_sescmd_init(prop, querybuf, packet_type, router_cli_ses);
|
||||||
|
|
||||||
/** Lock router session */
|
|
||||||
if (!rses_begin_locked_router_action(router_cli_ses))
|
|
||||||
{
|
|
||||||
rses_property_done(prop);
|
|
||||||
succp = false;
|
|
||||||
goto return_succp;
|
|
||||||
}
|
|
||||||
/** Add sescmd property to router client session */
|
/** Add sescmd property to router client session */
|
||||||
rses_property_add(router_cli_ses, prop);
|
rses_property_add(router_cli_ses, prop);
|
||||||
|
|
||||||
for (i=0; i<router_cli_ses->rses_nbackends; i++)
|
for (i=0; i<router_cli_ses->rses_nbackends; i++)
|
||||||
{
|
{
|
||||||
if (BREF_IS_IN_USE((&backend_ref[i])))
|
if (BREF_IS_IN_USE((&backend_ref[i])))
|
||||||
|
{
|
||||||
|
sescmd_cursor_t* scur;
|
||||||
|
|
||||||
|
scur = backend_ref_get_sescmd_cursor(&backend_ref[i]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This backend_ref waits reply, flag it.
|
||||||
|
*/
|
||||||
|
bref_set_state(get_bref_from_dcb(router_cli_ses,
|
||||||
|
backend_ref[i].bref_dcb),
|
||||||
|
BREF_WAITING_RESULT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start execution if cursor is not already executing.
|
||||||
|
* Otherwise, cursor will execute pending commands
|
||||||
|
* when it completes with previous commands.
|
||||||
|
*/
|
||||||
|
if (sescmd_cursor_is_active(scur))
|
||||||
|
{
|
||||||
|
succp = true;
|
||||||
|
|
||||||
|
LOGIF(LT, (skygw_log_write(
|
||||||
|
LOGFILE_TRACE,
|
||||||
|
"Backend %s:%d already executing sescmd.",
|
||||||
|
backend_ref[i].bref_backend->backend_server->name,
|
||||||
|
backend_ref[i].bref_backend->backend_server->port)));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
succp = execute_sescmd_in_backend(&backend_ref[i]);
|
succp = execute_sescmd_in_backend(&backend_ref[i]);
|
||||||
|
|
||||||
@ -2622,6 +2781,7 @@ static bool route_session_write(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/** Unlock router session */
|
/** Unlock router session */
|
||||||
rses_end_locked_router_action(router_cli_ses);
|
rses_end_locked_router_action(router_cli_ses);
|
||||||
|
|
||||||
@ -2696,6 +2856,7 @@ static void rwsplit_process_options(
|
|||||||
* Even if succp == true connecting to new slave may have failed. succp is to
|
* Even if succp == true connecting to new slave may have failed. succp is to
|
||||||
* tell whether router has enough master/slave connections to continue work.
|
* tell whether router has enough master/slave connections to continue work.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void handleError (
|
static void handleError (
|
||||||
ROUTER* instance,
|
ROUTER* instance,
|
||||||
void* router_session,
|
void* router_session,
|
||||||
@ -2719,10 +2880,6 @@ static void handleError (
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case ERRACT_NEW_CONNECTION:
|
case ERRACT_NEW_CONNECTION:
|
||||||
{
|
{
|
||||||
int router_nservers;
|
|
||||||
int max_nslaves;
|
|
||||||
backend_ref_t* bref;
|
|
||||||
|
|
||||||
CHK_CLIENT_RSES(rses);
|
CHK_CLIENT_RSES(rses);
|
||||||
|
|
||||||
if (!rses_begin_locked_router_action(rses))
|
if (!rses_begin_locked_router_action(rses))
|
||||||
@ -2731,14 +2888,78 @@ static void handleError (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*succp = handle_error_new_connection(inst,
|
||||||
|
rses,
|
||||||
|
backend_dcb,
|
||||||
|
errmsgbuf);
|
||||||
|
rses_end_locked_router_action(rses);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ERRACT_REPLY_CLIENT:
|
||||||
|
{
|
||||||
|
*succp = handle_error_reply_client(session, errmsgbuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
*succp = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool handle_error_reply_client(
|
||||||
|
SESSION* ses,
|
||||||
|
GWBUF* errmsg)
|
||||||
|
{
|
||||||
|
session_state_t sesstate;
|
||||||
|
DCB* client_dcb;
|
||||||
|
bool succp;
|
||||||
|
|
||||||
|
spinlock_acquire(&ses->ses_lock);
|
||||||
|
sesstate = ses->state;
|
||||||
|
client_dcb = ses->client;
|
||||||
|
spinlock_release(&ses->ses_lock);
|
||||||
|
|
||||||
|
if (sesstate == SESSION_STATE_ROUTER_READY)
|
||||||
|
{
|
||||||
|
CHK_DCB(client_dcb);
|
||||||
|
client_dcb->func.write(client_dcb, errmsg);
|
||||||
|
}
|
||||||
|
succp = false; /** false because new servers aren's selected. */
|
||||||
|
|
||||||
|
return succp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This must be called with router lock
|
||||||
|
*/
|
||||||
|
static bool handle_error_new_connection(
|
||||||
|
ROUTER_INSTANCE* inst,
|
||||||
|
ROUTER_CLIENT_SES* rses,
|
||||||
|
DCB* backend_dcb,
|
||||||
|
GWBUF* errmsg)
|
||||||
|
{
|
||||||
|
SESSION* ses;
|
||||||
|
int router_nservers;
|
||||||
|
int max_nslaves;
|
||||||
|
backend_ref_t* bref;
|
||||||
|
bool succp;
|
||||||
|
|
||||||
|
ss_dassert(SPINLOCK_IS_LOCKED(&rses->rses_lock));
|
||||||
|
|
||||||
|
ses = backend_dcb->session;
|
||||||
|
CHK_SESSION(ses);
|
||||||
|
|
||||||
bref = get_bref_from_dcb(rses, backend_dcb);
|
bref = get_bref_from_dcb(rses, backend_dcb);
|
||||||
|
|
||||||
/** failed DCB has already been replaced */
|
/** failed DCB has already been replaced */
|
||||||
if (bref == NULL)
|
if (bref == NULL)
|
||||||
{
|
{
|
||||||
rses_end_locked_router_action(rses);
|
rses_end_locked_router_action(rses);
|
||||||
*succp = true;
|
succp = true;
|
||||||
return;
|
goto return_succp;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Error handler is already called for this DCB because
|
* Error handler is already called for this DCB because
|
||||||
@ -2748,8 +2969,8 @@ static void handleError (
|
|||||||
if (backend_dcb->state != DCB_STATE_POLLING)
|
if (backend_dcb->state != DCB_STATE_POLLING)
|
||||||
{
|
{
|
||||||
rses_end_locked_router_action(rses);
|
rses_end_locked_router_action(rses);
|
||||||
*succp = true;
|
succp = true;
|
||||||
return;
|
goto return_succp;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHK_BACKEND_REF(bref);
|
CHK_BACKEND_REF(bref);
|
||||||
@ -2757,12 +2978,11 @@ static void handleError (
|
|||||||
if (BREF_IS_WAITING_RESULT(bref))
|
if (BREF_IS_WAITING_RESULT(bref))
|
||||||
{
|
{
|
||||||
DCB* client_dcb;
|
DCB* client_dcb;
|
||||||
client_dcb = session->client;
|
client_dcb = ses->client;
|
||||||
client_dcb->func.write(client_dcb, errmsgbuf);
|
client_dcb->func.write(client_dcb, errmsg);
|
||||||
bref_clear_state(bref, BREF_WAITING_RESULT);
|
bref_clear_state(bref, BREF_WAITING_RESULT);
|
||||||
}
|
}
|
||||||
bref_clear_state(bref, BREF_IN_USE);
|
bref_clear_state(bref, BREF_IN_USE);
|
||||||
bref_set_state(bref, BREF_NOT_USED);
|
|
||||||
bref_set_state(bref, BREF_CLOSED);
|
bref_set_state(bref, BREF_CLOSED);
|
||||||
/**
|
/**
|
||||||
* Remove callback because this DCB won't be used
|
* Remove callback because this DCB won't be used
|
||||||
@ -2780,42 +3000,19 @@ static void handleError (
|
|||||||
* Try to get replacement slave or at least the minimum
|
* Try to get replacement slave or at least the minimum
|
||||||
* number of slave connections for router session.
|
* number of slave connections for router session.
|
||||||
*/
|
*/
|
||||||
*succp = select_connect_backend_servers(
|
succp = select_connect_backend_servers(
|
||||||
&rses->rses_master_ref,
|
&rses->rses_master_ref,
|
||||||
rses->rses_backend_ref,
|
rses->rses_backend_ref,
|
||||||
router_nservers,
|
router_nservers,
|
||||||
max_nslaves,
|
max_nslaves,
|
||||||
rses->rses_config.rw_slave_select_criteria,
|
rses->rses_config.rw_slave_select_criteria,
|
||||||
session,
|
ses,
|
||||||
inst);
|
inst);
|
||||||
|
|
||||||
rses_end_locked_router_action(rses);
|
return_succp:
|
||||||
break;
|
return succp;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ERRACT_REPLY_CLIENT:
|
|
||||||
{
|
|
||||||
session_state_t sesstate;
|
|
||||||
|
|
||||||
spinlock_acquire(&session->ses_lock);
|
|
||||||
sesstate = session->state;
|
|
||||||
client_dcb = session->client;
|
|
||||||
spinlock_release(&session->ses_lock);
|
|
||||||
|
|
||||||
if (sesstate == SESSION_STATE_ROUTER_READY)
|
|
||||||
{
|
|
||||||
CHK_DCB(client_dcb);
|
|
||||||
client_dcb->func.write(client_dcb, errmsgbuf);
|
|
||||||
}
|
|
||||||
succp = false; /** false because new servers aren's selected. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
*succp = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_error_packet(
|
static void print_error_packet(
|
||||||
ROUTER_CLIENT_SES* rses,
|
ROUTER_CLIENT_SES* rses,
|
||||||
@ -2823,7 +3020,7 @@ static void print_error_packet(
|
|||||||
DCB* dcb)
|
DCB* dcb)
|
||||||
{
|
{
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
if (buf->gwbuf_type == GWBUF_TYPE_MYSQL)
|
if (GWBUF_IS_TYPE_MYSQL(buf))
|
||||||
{
|
{
|
||||||
while (gwbuf_length(buf) > 0)
|
while (gwbuf_length(buf) > 0)
|
||||||
{
|
{
|
||||||
@ -2977,3 +3174,71 @@ static int router_handle_state_switch(
|
|||||||
return_rc:
|
return_rc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static sescmd_cursor_t* backend_ref_get_sescmd_cursor (
|
||||||
|
backend_ref_t* bref)
|
||||||
|
{
|
||||||
|
sescmd_cursor_t* scur;
|
||||||
|
CHK_BACKEND_REF(bref);
|
||||||
|
|
||||||
|
scur = &bref->bref_sescmd_cur;
|
||||||
|
CHK_SESCMD_CUR(scur);
|
||||||
|
|
||||||
|
return scur;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PREP_STMT_CACHING)
|
||||||
|
#define MAX_STMT_LEN 1024
|
||||||
|
|
||||||
|
static prep_stmt_t* prep_stmt_init(
|
||||||
|
prep_stmt_type_t type,
|
||||||
|
void* id)
|
||||||
|
{
|
||||||
|
prep_stmt_t* pstmt;
|
||||||
|
|
||||||
|
pstmt = (prep_stmt_t *)calloc(1, sizeof(prep_stmt_t));
|
||||||
|
|
||||||
|
if (pstmt != NULL)
|
||||||
|
{
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
pstmt->pstmt_chk_top = CHK_NUM_PREP_STMT;
|
||||||
|
pstmt->pstmt_chk_tail = CHK_NUM_PREP_STMT;
|
||||||
|
#endif
|
||||||
|
pstmt->pstmt_state = PREP_STMT_ALLOC;
|
||||||
|
pstmt->pstmt_type = type;
|
||||||
|
|
||||||
|
if (type == PREP_STMT_NAME)
|
||||||
|
{
|
||||||
|
pstmt->pstmt_id.name = strndup((char *)id, MAX_STMT_LEN);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pstmt->pstmt_id.seq = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHK_PREP_STMT(pstmt);
|
||||||
|
return pstmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prep_stmt_done(
|
||||||
|
prep_stmt_t* pstmt)
|
||||||
|
{
|
||||||
|
CHK_PREP_STMT(pstmt);
|
||||||
|
|
||||||
|
if (pstmt->pstmt_type == PREP_STMT_NAME)
|
||||||
|
{
|
||||||
|
free(pstmt->pstmt_id.name);
|
||||||
|
}
|
||||||
|
free(pstmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool prep_stmt_drop(
|
||||||
|
prep_stmt_t* pstmt)
|
||||||
|
{
|
||||||
|
CHK_PREP_STMT(pstmt);
|
||||||
|
|
||||||
|
pstmt->pstmt_state = PREP_STMT_DROPPED;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif /*< PREP_STMT_CACHING */
|
||||||
|
@ -122,7 +122,8 @@ typedef enum skygw_chk_t {
|
|||||||
CHK_NUM_ROUTER_PROPERTY,
|
CHK_NUM_ROUTER_PROPERTY,
|
||||||
CHK_NUM_SESCMD_CUR,
|
CHK_NUM_SESCMD_CUR,
|
||||||
CHK_NUM_BACKEND,
|
CHK_NUM_BACKEND,
|
||||||
CHK_NUM_BACKEND_REF
|
CHK_NUM_BACKEND_REF,
|
||||||
|
CHK_NUM_PREP_STMT
|
||||||
} skygw_chk_t;
|
} skygw_chk_t;
|
||||||
|
|
||||||
# define STRBOOL(b) ((b) ? "true" : "false")
|
# define STRBOOL(b) ((b) ? "true" : "false")
|
||||||
@ -140,23 +141,26 @@ typedef enum skygw_chk_t {
|
|||||||
((i) == LOGFILE_DEBUG ? "LOGFILE_DEBUG" : \
|
((i) == LOGFILE_DEBUG ? "LOGFILE_DEBUG" : \
|
||||||
"Unknown logfile type"))))
|
"Unknown logfile type"))))
|
||||||
|
|
||||||
#define STRPACKETTYPE(p) ((p) == COM_INIT_DB ? "COM_INIT_DB" : \
|
#define STRPACKETTYPE(p) ((p) == MYSQL_COM_INIT_DB ? "COM_INIT_DB" : \
|
||||||
((p) == COM_CREATE_DB ? "COM_CREATE_DB" : \
|
((p) == MYSQL_COM_CREATE_DB ? "COM_CREATE_DB" : \
|
||||||
((p) == COM_DROP_DB ? "COM_DROP_DB" : \
|
((p) == MYSQL_COM_DROP_DB ? "COM_DROP_DB" : \
|
||||||
((p) == COM_REFRESH ? "COM_REFRESH" : \
|
((p) == MYSQL_COM_REFRESH ? "COM_REFRESH" : \
|
||||||
((p) == COM_DEBUG ? "COM_DEBUG" : \
|
((p) == MYSQL_COM_DEBUG ? "COM_DEBUG" : \
|
||||||
((p) == COM_PING ? "COM_PING" : \
|
((p) == MYSQL_COM_PING ? "COM_PING" : \
|
||||||
((p) == COM_CHANGE_USER ? "COM_CHANGE_USER" : \
|
((p) == MYSQL_COM_CHANGE_USER ? "COM_CHANGE_USER" : \
|
||||||
((p) == COM_QUERY ? "COM_QUERY" : \
|
((p) == MYSQL_COM_QUERY ? "COM_QUERY" : \
|
||||||
((p) == COM_SHUTDOWN ? "COM_SHUTDOWN" : \
|
((p) == MYSQL_COM_SHUTDOWN ? "COM_SHUTDOWN" : \
|
||||||
((p) == COM_PROCESS_INFO ? "COM_PROCESS_INFO" : \
|
((p) == MYSQL_COM_PROCESS_INFO ? "COM_PROCESS_INFO" : \
|
||||||
((p) == COM_CONNECT ? "COM_CONNECT" : \
|
((p) == MYSQL_COM_CONNECT ? "COM_CONNECT" : \
|
||||||
((p) == COM_PROCESS_KILL ? "COM_PROCESS_KILL" : \
|
((p) == MYSQL_COM_PROCESS_KILL ? "COM_PROCESS_KILL" : \
|
||||||
((p) == COM_TIME ? "COM_TIME" : \
|
((p) == MYSQL_COM_TIME ? "COM_TIME" : \
|
||||||
((p) == COM_DELAYED_INSERT ? "COM_DELAYED_INSERT" : \
|
((p) == MYSQL_COM_DELAYED_INSERT ? "COM_DELAYED_INSERT" : \
|
||||||
((p) == COM_DAEMON ? "COM_DAEMON" : \
|
((p) == MYSQL_COM_DAEMON ? "COM_DAEMON" : \
|
||||||
((p) == COM_QUIT ? "COM_QUIT" : \
|
((p) == MYSQL_COM_QUIT ? "COM_QUIT" : \
|
||||||
"UNKNOWN MYSQL PACKET TYPE"))))))))))))))))
|
((p) == MYSQL_COM_STMT_PREPARE ? "MYSQL_COM_STMT_PREPARE" : \
|
||||||
|
((p) == MYSQL_COM_STMT_EXECUTE ? "MYSQL_COM_STMT_EXECUTE" : \
|
||||||
|
((p) == MYSQL_COM_UNDEFINED ? "MYSQL_COM_UNDEFINED" : \
|
||||||
|
"UNKNOWN MYSQL PACKET TYPE")))))))))))))))))))
|
||||||
|
|
||||||
#define STRDCBSTATE(s) ((s) == DCB_STATE_ALLOC ? "DCB_STATE_ALLOC" : \
|
#define STRDCBSTATE(s) ((s) == DCB_STATE_ALLOC ? "DCB_STATE_ALLOC" : \
|
||||||
((s) == DCB_STATE_POLLING ? "DCB_STATE_POLLING" : \
|
((s) == DCB_STATE_POLLING ? "DCB_STATE_POLLING" : \
|
||||||
@ -180,10 +184,7 @@ typedef enum skygw_chk_t {
|
|||||||
((s) == MYSQL_AUTH_RECV ? "MYSQL_AUTH_RECV" : \
|
((s) == MYSQL_AUTH_RECV ? "MYSQL_AUTH_RECV" : \
|
||||||
((s) == MYSQL_AUTH_FAILED ? "MYSQL_AUTH_FAILED" : \
|
((s) == MYSQL_AUTH_FAILED ? "MYSQL_AUTH_FAILED" : \
|
||||||
((s) == MYSQL_IDLE ? "MYSQL_IDLE" : \
|
((s) == MYSQL_IDLE ? "MYSQL_IDLE" : \
|
||||||
((s) == MYSQL_ROUTING ? "MYSQL_ROUTING" : \
|
"UNKNOWN MYSQL STATE")))))))
|
||||||
((s) == MYSQL_WAITING_RESULT ? "MYSQL_WAITING_RESULT" : \
|
|
||||||
((s) == MYSQL_SESSION_CHANGE ? "MYSQL_SESSION_CHANGE" : \
|
|
||||||
"UNKNOWN MYSQL STATE"))))))))))
|
|
||||||
|
|
||||||
#define STRITEMTYPE(t) ((t) == Item::FIELD_ITEM ? "FIELD_ITEM" : \
|
#define STRITEMTYPE(t) ((t) == Item::FIELD_ITEM ? "FIELD_ITEM" : \
|
||||||
((t) == Item::FUNC_ITEM ? "FUNC_ITEM" : \
|
((t) == Item::FUNC_ITEM ? "FUNC_ITEM" : \
|
||||||
@ -478,6 +479,12 @@ typedef enum skygw_chk_t {
|
|||||||
"Backend reference has invalid check fields"); \
|
"Backend reference has invalid check fields"); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CHK_PREP_STMT(p) { \
|
||||||
|
ss_info_dassert((p)->pstmt_chk_top == CHK_NUM_PREP_STMT && \
|
||||||
|
(p)->pstmt_chk_tail == CHK_NUM_PREP_STMT, \
|
||||||
|
"Prepared statement struct has invalid check fields"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
bool conn_open[10240];
|
bool conn_open[10240];
|
||||||
|
Reference in New Issue
Block a user