Merge branch 'SESvars' of https://github.com/skysql/MaxScale into SESvars
Conflicts: server/core/dcb.c server/core/poll.c server/modules/include/mysql_client_server_protocol.h server/modules/routing/readwritesplit/readwritesplit.c
This commit is contained in:
commit
c356b396a6
@ -81,6 +81,7 @@ SHARED_BUF *sbuf;
|
||||
sbuf->refcount = 1;
|
||||
rval->sbuf = sbuf;
|
||||
rval->next = NULL;
|
||||
rval->gwbuf_type = GWBUF_TYPE_UNDEFINED;
|
||||
rval->command = 0;
|
||||
CHK_GWBUF(rval);
|
||||
return rval;
|
||||
@ -127,11 +128,93 @@ GWBUF *rval;
|
||||
rval->sbuf = buf->sbuf;
|
||||
rval->start = buf->start;
|
||||
rval->end = buf->end;
|
||||
rval->gwbuf_type = buf->gwbuf_type;
|
||||
rval->next = NULL;
|
||||
rval->command = buf->command;
|
||||
CHK_GWBUF(rval);
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
GWBUF *gwbuf_clone_portion(
|
||||
GWBUF *buf,
|
||||
size_t start_offset,
|
||||
size_t length)
|
||||
{
|
||||
GWBUF* clonebuf;
|
||||
|
||||
CHK_GWBUF(buf);
|
||||
ss_dassert(start_offset+length <= GWBUF_LENGTH(buf));
|
||||
|
||||
if ((clonebuf = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
atomic_add(&buf->sbuf->refcount, 1);
|
||||
clonebuf->sbuf = buf->sbuf;
|
||||
clonebuf->start = (void *)((char*)buf->start)+start_offset;
|
||||
clonebuf->end = (void *)((char *)clonebuf->start)+length;
|
||||
clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone the type for now */
|
||||
clonebuf->next = NULL;
|
||||
CHK_GWBUF(clonebuf);
|
||||
return clonebuf;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pointer to GWBUF of a requested type.
|
||||
* As of 10.3.14 only MySQL to plain text conversion is supported.
|
||||
* Return NULL if conversion between types is not supported or due lacking
|
||||
* type information.
|
||||
*/
|
||||
GWBUF *gwbuf_clone_transform(
|
||||
GWBUF * head,
|
||||
gwbuf_type_t targettype)
|
||||
{
|
||||
gwbuf_type_t src_type;
|
||||
GWBUF* clonebuf;
|
||||
|
||||
CHK_GWBUF(head);
|
||||
src_type = head->gwbuf_type;
|
||||
|
||||
if (targettype == GWBUF_TYPE_UNDEFINED ||
|
||||
src_type == GWBUF_TYPE_UNDEFINED ||
|
||||
src_type == GWBUF_TYPE_PLAINSQL ||
|
||||
targettype == src_type)
|
||||
{
|
||||
clonebuf = NULL;
|
||||
goto return_clonebuf;
|
||||
}
|
||||
|
||||
switch (src_type)
|
||||
{
|
||||
case GWBUF_TYPE_MYSQL:
|
||||
if (targettype == GWBUF_TYPE_PLAINSQL)
|
||||
{
|
||||
/** Crete reference to string part of buffer */
|
||||
clonebuf = gwbuf_clone_portion(
|
||||
head,
|
||||
5,
|
||||
GWBUF_LENGTH(head)-5);
|
||||
ss_dassert(clonebuf != NULL);
|
||||
/** Overwrite the type with new format */
|
||||
clonebuf->gwbuf_type = targettype;
|
||||
}
|
||||
else
|
||||
{
|
||||
clonebuf = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
clonebuf = NULL;
|
||||
break;
|
||||
} /*< switch (src_type) */
|
||||
|
||||
return_clonebuf:
|
||||
return clonebuf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append a buffer onto a linked list of buffer structures.
|
||||
*
|
||||
@ -150,6 +233,7 @@ GWBUF *ptr = head;
|
||||
if (!head)
|
||||
return tail;
|
||||
CHK_GWBUF(head);
|
||||
CHK_GWBUF(tail);
|
||||
while (ptr->next)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
@ -178,9 +262,10 @@ GWBUF *
|
||||
gwbuf_consume(GWBUF *head, unsigned int length)
|
||||
{
|
||||
GWBUF *rval = head;
|
||||
|
||||
CHK_GWBUF(head);
|
||||
GWBUF_CONSUME(head, length);
|
||||
CHK_GWBUF(head);
|
||||
|
||||
if (GWBUF_EMPTY(head))
|
||||
{
|
||||
rval = head->next;
|
||||
@ -207,3 +292,28 @@ int rval = 0;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool gwbuf_set_type(
|
||||
GWBUF* buf,
|
||||
gwbuf_type_t type)
|
||||
{
|
||||
bool succp;
|
||||
CHK_GWBUF(buf);
|
||||
|
||||
switch (type) {
|
||||
case GWBUF_TYPE_MYSQL:
|
||||
case GWBUF_TYPE_PLAINSQL:
|
||||
case GWBUF_TYPE_UNDEFINED:
|
||||
buf->gwbuf_type = type;
|
||||
succp = true;
|
||||
break;
|
||||
default:
|
||||
succp = false;
|
||||
break;
|
||||
}
|
||||
ss_dassert(succp);
|
||||
return succp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -303,12 +303,8 @@ dcb_final_free(DCB *dcb)
|
||||
if (dcb->remote)
|
||||
free(dcb->remote);
|
||||
bitmask_free(&dcb->memdata.bitmask);
|
||||
|
||||
#if 1
|
||||
simple_mutex_done(&dcb->dcb_read_lock);
|
||||
simple_mutex_done(&dcb->dcb_write_lock);
|
||||
#endif
|
||||
|
||||
free(dcb);
|
||||
}
|
||||
|
||||
@ -527,6 +523,8 @@ int rc;
|
||||
* Successfully connected to backend. Assign file descriptor to dcb
|
||||
*/
|
||||
dcb->fd = fd;
|
||||
/** Copy status field to DCB */
|
||||
dcb->dcb_server_status = server->status;
|
||||
|
||||
/*<
|
||||
* backend_dcb is connected to backend server, and once backend_dcb
|
||||
@ -690,10 +688,18 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
||||
dcb->state != DCB_STATE_LISTENING &&
|
||||
dcb->state != DCB_STATE_NOPOLLING))
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Write aborted to dcb %p because "
|
||||
"it is in state %s",
|
||||
pthread_self(),
|
||||
dcb->stats.n_buffered,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
spinlock_acquire(&dcb->writeqlock);
|
||||
|
||||
if (dcb->writeq != NULL)
|
||||
@ -750,7 +756,11 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
||||
#endif /* SS_DEBUG */
|
||||
len = GWBUF_LENGTH(queue);
|
||||
GW_NOINTR_CALL(
|
||||
w = gw_write(dcb->fd, GWBUF_DATA(queue), len);
|
||||
w = gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
dcb,
|
||||
#endif
|
||||
dcb->fd, GWBUF_DATA(queue), len);
|
||||
dcb->stats.n_writes++;
|
||||
);
|
||||
|
||||
@ -759,6 +769,8 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
||||
saved_errno = errno;
|
||||
errno = 0;
|
||||
|
||||
if (LOG_IS_ENABLED(LOGFILE_DEBUG))
|
||||
{
|
||||
if (saved_errno == EPIPE) {
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
@ -771,7 +783,12 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
||||
dcb->fd,
|
||||
saved_errno,
|
||||
strerror(saved_errno))));
|
||||
} else if (saved_errno != EAGAIN &&
|
||||
}
|
||||
}
|
||||
if (LOG_IS_ENABLED(LOGFILE_ERROR))
|
||||
{
|
||||
if (saved_errno != EPIPE &&
|
||||
saved_errno != EAGAIN &&
|
||||
saved_errno != EWOULDBLOCK)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
@ -785,6 +802,7 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
||||
saved_errno,
|
||||
strerror(saved_errno))));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
@ -799,9 +817,9 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
||||
pthread_self(),
|
||||
w,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
}
|
||||
} /*< while (queue != NULL) */
|
||||
/*<
|
||||
* What wasn't successfully written is stored to write queue
|
||||
* for suspended write.
|
||||
@ -819,7 +837,6 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
||||
saved_errno != EAGAIN &&
|
||||
saved_errno != EWOULDBLOCK)
|
||||
{
|
||||
queue = gwbuf_consume(queue, gwbuf_length(queue));
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Writing to %s socket failed due %d, %s.",
|
||||
@ -862,9 +879,13 @@ int saved_errno = 0;
|
||||
while (dcb->writeq != NULL)
|
||||
{
|
||||
len = GWBUF_LENGTH(dcb->writeq);
|
||||
GW_NOINTR_CALL(w = gw_write(dcb->fd,
|
||||
GWBUF_DATA(dcb->writeq),
|
||||
len););
|
||||
GW_NOINTR_CALL(w = gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
dcb,
|
||||
#endif
|
||||
dcb->fd,
|
||||
GWBUF_DATA(dcb->writeq),
|
||||
len););
|
||||
saved_errno = errno;
|
||||
errno = 0;
|
||||
|
||||
@ -1319,12 +1340,15 @@ static bool dcb_set_state_nomutex(
|
||||
}
|
||||
|
||||
int gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
DCB* dcb,
|
||||
#endif
|
||||
int fd,
|
||||
const void* buf,
|
||||
size_t nbytes)
|
||||
{
|
||||
int w;
|
||||
#if defined(SS_DEBUG)
|
||||
#if defined(SS_DEBUG)
|
||||
if (dcb_fake_write_errno[fd] != 0) {
|
||||
ss_dassert(dcb_fake_write_ev[fd] != 0);
|
||||
w = write(fd, buf, nbytes/2); /*< leave peer to read missing bytes */
|
||||
@ -1339,6 +1363,57 @@ int gw_write(
|
||||
#else
|
||||
w = write(fd, buf, nbytes);
|
||||
#endif /* SS_DEBUG && SS_TEST */
|
||||
|
||||
#if defined(SS_DEBUG_MYSQL)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t* packet = (uint8_t *)buf;
|
||||
char* str;
|
||||
|
||||
/** Print only MySQL packets */
|
||||
if (w > 5)
|
||||
{
|
||||
str = (char *)&packet[5];
|
||||
len = packet[0];
|
||||
len += 256*packet[1];
|
||||
len += 256*256*packet[2];
|
||||
|
||||
if (strncmp(str, "insert", 6) == 0 ||
|
||||
strncmp(str, "create", 6) == 0 ||
|
||||
strncmp(str, "drop", 4) == 0)
|
||||
{
|
||||
ss_dassert((dcb->dcb_server_status & (SERVER_RUNNING|SERVER_MASTER|SERVER_SLAVE))==(SERVER_RUNNING|SERVER_MASTER));
|
||||
}
|
||||
|
||||
if (strncmp(str, "set autocommit", 14) == 0 && nbytes > 17)
|
||||
{
|
||||
char* s = (char *)calloc(1, nbytes+1);
|
||||
|
||||
if (nbytes-5 > len)
|
||||
{
|
||||
size_t len2 = packet[4+len];
|
||||
len2 += 256*packet[4+len+1];
|
||||
len2 += 256*256*packet[4+len+2];
|
||||
|
||||
char* str2 = (char *)&packet[4+len+5];
|
||||
snprintf(s, 5+len+len2, "long %s %s", (char *)str, (char *)str2);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(s, len, "%s", (char *)str);
|
||||
}
|
||||
LOGIF(LT, (skygw_log_write(
|
||||
LOGFILE_TRACE,
|
||||
"%lu [gw_write] Wrote %d bytes : %s ",
|
||||
pthread_self(),
|
||||
w,
|
||||
s)));
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
|
@ -363,7 +363,6 @@ poll_waitevents(void *arg)
|
||||
eno = gw_getsockerrno(dcb->fd);
|
||||
|
||||
if (eno == 0) {
|
||||
#if 1
|
||||
simple_mutex_lock(
|
||||
&dcb->dcb_write_lock,
|
||||
true);
|
||||
@ -371,16 +370,13 @@ poll_waitevents(void *arg)
|
||||
!dcb->dcb_write_active,
|
||||
"Write already active");
|
||||
dcb->dcb_write_active = TRUE;
|
||||
#endif
|
||||
atomic_add(
|
||||
&pollStats.n_write,
|
||||
1);
|
||||
dcb->func.write_ready(dcb);
|
||||
#if 1
|
||||
dcb->dcb_write_active = FALSE;
|
||||
simple_mutex_unlock(
|
||||
&dcb->dcb_write_lock);
|
||||
#endif
|
||||
} else {
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
@ -396,13 +392,12 @@ poll_waitevents(void *arg)
|
||||
}
|
||||
if (ev & EPOLLIN)
|
||||
{
|
||||
#if 1
|
||||
simple_mutex_lock(&dcb->dcb_read_lock,
|
||||
true);
|
||||
ss_info_dassert(!dcb->dcb_read_active,
|
||||
"Read already active");
|
||||
dcb->dcb_read_active = TRUE;
|
||||
#endif
|
||||
|
||||
if (dcb->state == DCB_STATE_LISTENING)
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
@ -427,11 +422,9 @@ poll_waitevents(void *arg)
|
||||
atomic_add(&pollStats.n_read, 1);
|
||||
dcb->func.read(dcb);
|
||||
}
|
||||
#if 1
|
||||
dcb->dcb_read_active = FALSE;
|
||||
simple_mutex_unlock(
|
||||
&dcb->dcb_read_lock);
|
||||
#endif
|
||||
}
|
||||
if (ev & EPOLLERR)
|
||||
{
|
||||
@ -462,6 +455,7 @@ poll_waitevents(void *arg)
|
||||
atomic_add(&pollStats.n_error, 1);
|
||||
dcb->func.error(dcb);
|
||||
}
|
||||
|
||||
if (ev & EPOLLHUP)
|
||||
{
|
||||
int eno = 0;
|
||||
|
@ -41,9 +41,18 @@
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
#include <skygw_debug.h>
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GWBUF_TYPE_UNDEFINED = 0x0,
|
||||
GWBUF_TYPE_PLAINSQL = 0x1,
|
||||
GWBUF_TYPE_MYSQL = 0x2
|
||||
} gwbuf_type_t;
|
||||
|
||||
/**
|
||||
* A structure to encapsualte 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
|
||||
* shared between multiple GWBUF's without the need to make multiple copies
|
||||
* but still maintain separate data pointers.
|
||||
*/
|
||||
@ -64,8 +73,9 @@ typedef struct gwbuf {
|
||||
struct gwbuf *next; /*< Next buffer in a linked chain of buffers */
|
||||
void *start; /*< Start of the valid data */
|
||||
void *end; /*< First byte after the valid data */
|
||||
SHARED_BUF *sbuf; /*< The shared buffer with the real data */
|
||||
SHARED_BUF *sbuf; /*< The shared buffer with the real data */
|
||||
int command;/*< The command type for the queue */
|
||||
gwbuf_type_t gwbuf_type; /*< buffer's data type information */
|
||||
} GWBUF;
|
||||
|
||||
/*<
|
||||
@ -83,6 +93,7 @@ typedef struct gwbuf {
|
||||
/*< Consume a number of bytes in the buffer */
|
||||
#define GWBUF_CONSUME(b, bytes) (b)->start += bytes
|
||||
|
||||
#define GWBUF_TYPE(b) (b)->gwbuf_type
|
||||
/*<
|
||||
* Function prototypes for the API to maniplate the buffers
|
||||
*/
|
||||
@ -92,6 +103,7 @@ extern GWBUF *gwbuf_clone(GWBUF *buf);
|
||||
extern GWBUF *gwbuf_append(GWBUF *head, GWBUF *tail);
|
||||
extern GWBUF *gwbuf_consume(GWBUF *head, unsigned int length);
|
||||
extern unsigned int gwbuf_length(GWBUF *head);
|
||||
|
||||
|
||||
extern GWBUF *gwbuf_clone_portion(GWBUF *head, size_t offset, size_t len);
|
||||
extern GWBUF *gwbuf_clone_transform(GWBUF *head, gwbuf_type_t type);
|
||||
extern bool gwbuf_set_type(GWBUF *head, gwbuf_type_t type);
|
||||
#endif
|
||||
|
@ -179,7 +179,7 @@ typedef struct dcb {
|
||||
SPINLOCK authlock; /**< Generic Authorization spinlock */
|
||||
|
||||
DCBSTATS stats; /**< DCB related statistics */
|
||||
|
||||
unsigned int dcb_server_status; /*< the server role indicator from SERVER */
|
||||
struct dcb *next; /**< Next DCB in the chain of allocated DCB's */
|
||||
struct service *service; /**< The related service */
|
||||
void *data; /**< Specific client data */
|
||||
@ -205,7 +205,13 @@ int fail_accept_errno;
|
||||
#define DCB_ISZOMBIE(x) ((x)->state == DCB_STATE_ZOMBIE)
|
||||
|
||||
DCB *dcb_get_zombies(void);
|
||||
int gw_write(int fd, const void* buf, size_t nbytes);
|
||||
int gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
DCB* dcb,
|
||||
#endif
|
||||
int fd,
|
||||
const void* buf,
|
||||
size_t nbytes);
|
||||
int dcb_write(DCB *, GWBUF *);
|
||||
DCB *dcb_alloc(dcb_role_t);
|
||||
void dcb_free(DCB *);
|
||||
|
@ -54,6 +54,12 @@ int do_read_dcb(DCB *dcb);
|
||||
int do_read_10(DCB *dcb, uint8_t *buffer);
|
||||
int MySQLWrite(DCB *dcb, GWBUF *queue);
|
||||
int setnonblocking(int fd);
|
||||
int gw_write(int fd, const void* buf, size_t nbytes);
|
||||
int gw_write(
|
||||
#if defined(SS_DEBUG)
|
||||
DCB* dcb,
|
||||
#endif
|
||||
int fd,
|
||||
const void* buf,
|
||||
size_t nbytes);
|
||||
int gw_getsockerrno(int fd);
|
||||
int parse_bindconfig(char *, unsigned short, struct sockaddr_in *);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <service.h>
|
||||
#include <session.h>
|
||||
#include <buffer.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* The ROUTER handle points to module specific data, so the best we can do
|
||||
@ -74,10 +75,13 @@ typedef struct router_object {
|
||||
void (*diagnostics)(ROUTER *instance, DCB *dcb);
|
||||
void (*clientReply)(ROUTER* instance, void* router_session, GWBUF* queue, DCB *backend_dcb);
|
||||
void (*errorReply)(ROUTER* instance, void* router_session, char* message, DCB *backend_dcb, int action);
|
||||
uint8_t (*getCapabilities)(ROUTER *instance, void* router_session);
|
||||
} ROUTER_OBJECT;
|
||||
|
||||
/* Router commands */
|
||||
#define ROUTER_DEFAULT 0 /**< Standard routing */
|
||||
#define ROUTER_CHANGE_SESSION 1 /**< Route a change session */
|
||||
typedef enum router_capability_t {
|
||||
RCAP_TYPE_UNDEFINED = 0,
|
||||
RCAP_TYPE_STMT_INPUT = (1 << 0),
|
||||
RCAP_TYPE_PACKET_INPUT = (1 << 1)
|
||||
} router_capability_t;
|
||||
|
||||
#endif
|
||||
|
@ -53,6 +53,8 @@ typedef struct spinlock {
|
||||
#define SPINLOCK_INIT { 0 }
|
||||
#endif
|
||||
|
||||
#define SPINLOCK_IS_LOCKED(l) ((l)->lock != 0 ? true : false)
|
||||
|
||||
extern void spinlock_init(SPINLOCK *lock);
|
||||
extern void spinlock_acquire(SPINLOCK *lock);
|
||||
extern int spinlock_acquire_nowait(SPINLOCK *lock);
|
||||
|
@ -297,6 +297,7 @@ void gw_str_xor(
|
||||
const uint8_t *input1,
|
||||
const uint8_t *input2,
|
||||
unsigned int len);
|
||||
<<<<<<< HEAD
|
||||
char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len);
|
||||
int gw_hex2bin(uint8_t *out, const char *in, unsigned int len);
|
||||
int gw_generate_random_str(char *output, int len);
|
||||
@ -304,3 +305,13 @@ char *gw_strend(register const char *s);
|
||||
int setnonblocking(int fd);
|
||||
int setipaddress(struct in_addr *a, char *p);
|
||||
int gw_read_gwbuff(DCB *dcb, GWBUF **head, int b);
|
||||
=======
|
||||
char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len);
|
||||
int gw_hex2bin(uint8_t *out, const char *in, unsigned int len);
|
||||
int gw_generate_random_str(char *output, int len);
|
||||
char *gw_strend(register const char *s);
|
||||
int setnonblocking(int fd);
|
||||
void setipaddress(struct in_addr *a, char *p);
|
||||
int gw_read_gwbuff(DCB *dcb, GWBUF **head, int b);
|
||||
GWBUF* gw_MySQL_get_next_stmt(GWBUF** p_readbuf);
|
||||
>>>>>>> 67d9b3afb94559f13b44780c9c54760b667a068a
|
||||
|
@ -53,8 +53,8 @@ typedef struct router_client_session {
|
||||
bool rses_closed; /*< true when closeSession is called */
|
||||
BACKEND *backend; /*< Backend used by the client session */
|
||||
DCB *backend_dcb; /*< DCB Connection to the backend */
|
||||
struct router_client_session
|
||||
*next;
|
||||
struct router_client_session *next;
|
||||
int rses_capabilities; /*< input type, for example */
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t rses_chk_tail;
|
||||
#endif
|
||||
|
@ -24,7 +24,7 @@
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* bazaar..
|
||||
* See GitHub https://github.com/skysql/MaxScale
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -41,25 +41,91 @@ typedef struct backend {
|
||||
int backend_conn_count; /*< Number of connections to the server */
|
||||
} BACKEND;
|
||||
|
||||
typedef struct rses_property_st rses_property_t;
|
||||
typedef struct router_client_session ROUTER_CLIENT_SES;
|
||||
|
||||
typedef enum rses_property_type_t {
|
||||
RSES_PROP_TYPE_UNDEFINED=0,
|
||||
RSES_PROP_TYPE_SESCMD,
|
||||
RSES_PROP_TYPE_FIRST = RSES_PROP_TYPE_SESCMD,
|
||||
RSES_PROP_TYPE_LAST=RSES_PROP_TYPE_SESCMD,
|
||||
RSES_PROP_TYPE_COUNT=RSES_PROP_TYPE_LAST+1
|
||||
} rses_property_type_t;
|
||||
|
||||
typedef enum backend_type_t {
|
||||
BE_UNDEFINED=-1,
|
||||
BE_MASTER,
|
||||
BE_SLAVE,
|
||||
BE_COUNT
|
||||
} backend_type_t;
|
||||
|
||||
/**
|
||||
* Session variable command
|
||||
*/
|
||||
typedef struct mysql_sescmd_st {
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t my_sescmd_chk_top;
|
||||
#endif
|
||||
rses_property_t* my_sescmd_prop; /*< parent property */
|
||||
GWBUF* my_sescmd_buf; /*< query buffer */
|
||||
unsigned char my_sescmd_packet_type;/*< packet type */
|
||||
bool my_sescmd_is_replied; /*< is cmd replied to client */
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t my_sescmd_chk_tail;
|
||||
#endif
|
||||
} mysql_sescmd_t;
|
||||
|
||||
|
||||
/**
|
||||
* Property structure
|
||||
*/
|
||||
struct rses_property_st {
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t rses_prop_chk_top;
|
||||
#endif
|
||||
ROUTER_CLIENT_SES* rses_prop_rsession; /*< parent router session */
|
||||
int rses_prop_refcount;
|
||||
rses_property_type_t rses_prop_type;
|
||||
union rses_prop_data {
|
||||
mysql_sescmd_t sescmd;
|
||||
void* placeholder; /*< to be removed due new type */
|
||||
} rses_prop_data;
|
||||
rses_property_t* rses_prop_next; /*< next property of same type */
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t rses_prop_chk_tail;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct sescmd_cursor_st {
|
||||
ROUTER_CLIENT_SES* scmd_cur_rses; /*< pointer to owning router session */
|
||||
rses_property_t** scmd_cur_ptr_property; /*< address of pointer to owner property */
|
||||
mysql_sescmd_t* scmd_cur_cmd; /*< pointer to current session command */
|
||||
bool scmd_cur_active; /*< true if command is being executed */
|
||||
backend_type_t scmd_cur_be_type; /*< BE_MASTER or BE_SLAVE */
|
||||
} sescmd_cursor_t;
|
||||
|
||||
/**
|
||||
* The client session structure used within this router.
|
||||
*/
|
||||
typedef struct router_client_session {
|
||||
struct router_client_session {
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t rses_chk_top;
|
||||
skygw_chk_t rses_chk_top;
|
||||
#endif
|
||||
SPINLOCK rses_lock; /*< protects rses_deleted */
|
||||
int rses_versno; /*< even = no active update, else odd */
|
||||
bool rses_closed; /*< true when closeSession is called */
|
||||
BACKEND* be_slave; /*< Slave backend used by client session */
|
||||
BACKEND* be_master; /*< Master backend used by client session */
|
||||
DCB* slave_dcb; /*< Slave connection */
|
||||
DCB* master_dcb; /*< Master connection */
|
||||
SPINLOCK rses_lock; /*< protects rses_deleted */
|
||||
int rses_versno; /*< even = no active update, else odd */
|
||||
bool rses_closed; /*< true when closeSession is called */
|
||||
/** Properties listed by their type */
|
||||
rses_property_t* rses_properties[RSES_PROP_TYPE_COUNT];
|
||||
BACKEND* rses_backend[BE_COUNT];/*< Backends used by client session */
|
||||
DCB* rses_dcb[BE_COUNT];
|
||||
/*< cursor is pointer and status variable to current session command */
|
||||
sescmd_cursor_t rses_cursor[BE_COUNT];
|
||||
int rses_capabilities; /*< input type, for example */
|
||||
struct router_client_session* next;
|
||||
#if defined(SS_DEBUG)
|
||||
skygw_chk_t rses_chk_tail;
|
||||
skygw_chk_t rses_chk_tail;
|
||||
#endif
|
||||
} ROUTER_CLIENT_SES;
|
||||
};
|
||||
|
||||
/**
|
||||
* The statistics for this router instance
|
||||
@ -88,5 +154,4 @@ typedef struct router_instance {
|
||||
struct router_instance* next; /*< Next router on the list */
|
||||
} ROUTER_INSTANCE;
|
||||
|
||||
|
||||
#endif
|
||||
#endif /*< _RWSPLITROUTER_H */
|
||||
|
@ -283,6 +283,8 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
}
|
||||
|
||||
if (backend_protocol->state == MYSQL_AUTH_FAILED) {
|
||||
|
||||
spinlock_acquire(&dcb->delayqlock);
|
||||
/*<
|
||||
* vraa : errorHandle
|
||||
* check the delayq before the reply
|
||||
@ -295,10 +297,12 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
0,
|
||||
"Connection to backend lost.");
|
||||
// consume all the delay queue
|
||||
dcb->delayq = gwbuf_consume(
|
||||
while ((dcb->delayq = gwbuf_consume(
|
||||
dcb->delayq,
|
||||
gwbuf_length(dcb->delayq));
|
||||
GWBUF_LENGTH(dcb->delayq))) != NULL);
|
||||
}
|
||||
spinlock_release(&dcb->delayqlock);
|
||||
|
||||
|
||||
/* try reload users' table for next connection */
|
||||
service_refresh_users(dcb->session->client->service);
|
||||
@ -350,7 +354,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
pthread_self(),
|
||||
dcb->fd,
|
||||
current_session->user)));
|
||||
|
||||
|
||||
/* check the delay queue and flush the data */
|
||||
if (dcb->delayq)
|
||||
{
|
||||
@ -524,7 +528,7 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
/*<
|
||||
* Don't write to backend if backend_dcb is not in poll set anymore.
|
||||
*/
|
||||
spinlock_acquire(&dcb->authlock);
|
||||
spinlock_acquire(&dcb->dcb_initlock);
|
||||
if (dcb->state != DCB_STATE_POLLING) {
|
||||
/*< vraa : errorHandle */
|
||||
/*< Free buffer memory */
|
||||
@ -539,10 +543,12 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
dcb->fd,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
|
||||
spinlock_release(&dcb->authlock);
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
|
||||
spinlock_acquire(&dcb->authlock);
|
||||
/*<
|
||||
* Now put the incoming data to the delay queue unless backend is
|
||||
* connected with auth ok
|
||||
@ -556,7 +562,6 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
dcb,
|
||||
dcb->fd,
|
||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
||||
|
||||
backend_set_delayqueue(dcb, queue);
|
||||
spinlock_release(&dcb->authlock);
|
||||
return 1;
|
||||
@ -565,8 +570,6 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
/*<
|
||||
* Now we set the last command received, from the current queue
|
||||
*/
|
||||
memcpy(&dcb->command, &queue->command, sizeof(dcb->command));
|
||||
|
||||
spinlock_release(&dcb->authlock);
|
||||
rc = dcb_write(dcb, queue);
|
||||
return rc;
|
||||
@ -804,12 +807,6 @@ static int backend_write_delayqueue(DCB *dcb)
|
||||
localq = dcb->delayq;
|
||||
dcb->delayq = NULL;
|
||||
|
||||
/*<
|
||||
* Now we set the last command received, from the delayed queue
|
||||
*/
|
||||
|
||||
memcpy(&dcb->command, &localq->command, sizeof(dcb->command));
|
||||
|
||||
spinlock_release(&dcb->delayqlock);
|
||||
rc = dcb_write(dcb, localq);
|
||||
|
||||
@ -851,15 +848,12 @@ static int gw_change_user(DCB *backend, SERVER *server, SESSION *in_session, GWB
|
||||
unsigned int auth_token_len = 0;
|
||||
uint8_t *auth_token = NULL;
|
||||
int rv = -1;
|
||||
int len = 0;
|
||||
int auth_ret = 1;
|
||||
|
||||
current_session = (MYSQL_session *)in_session->client->data;
|
||||
backend_protocol = backend->protocol;
|
||||
client_protocol = in_session->client->protocol;
|
||||
|
||||
queue->command = ROUTER_CHANGE_SESSION;
|
||||
|
||||
// now get the user, after 4 bytes header and 1 byte command
|
||||
client_auth_packet += 5;
|
||||
strcpy(username, (char *)client_auth_packet);
|
||||
@ -910,31 +904,14 @@ static int gw_change_user(DCB *backend, SERVER *server, SESSION *in_session, GWB
|
||||
|
||||
rv = gw_send_change_user_to_backend(database, username, client_sha1, backend_protocol);
|
||||
|
||||
/*<
|
||||
* The current queue was not handled by func.write() in gw_send_change_user_to_backend()
|
||||
* We wrote a new gwbuf
|
||||
* Set backend command here!
|
||||
*/
|
||||
memcpy(&backend->command, &queue->command, sizeof(backend->command));
|
||||
|
||||
/*<
|
||||
* Now copy new data into user session
|
||||
*/
|
||||
strcpy(current_session->user, username);
|
||||
strcpy(current_session->db, database);
|
||||
memcpy(current_session->client_sha1, client_sha1, sizeof(current_session->client_sha1));
|
||||
|
||||
}
|
||||
|
||||
// consume all the data received from client
|
||||
|
||||
spinlock_acquire(&backend->writeqlock);
|
||||
|
||||
len = gwbuf_length(queue);
|
||||
queue = gwbuf_consume(queue, len);
|
||||
|
||||
spinlock_release(&backend->writeqlock);
|
||||
|
||||
}
|
||||
gwbuf_free(queue);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -951,7 +928,6 @@ static int gw_session(DCB *backend_dcb, void *data) {
|
||||
GWBUF *queue = NULL;
|
||||
|
||||
queue = (GWBUF *) data;
|
||||
queue->command = ROUTER_CHANGE_SESSION;
|
||||
backend_dcb->func.write(backend_dcb, queue);
|
||||
|
||||
return 1;
|
||||
|
@ -57,6 +57,11 @@ static int gw_client_hangup_event(DCB *dcb);
|
||||
int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
|
||||
int MySQLSendHandshake(DCB* dcb);
|
||||
static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue);
|
||||
static int route_by_statement(
|
||||
ROUTER* router_instance,
|
||||
ROUTER_OBJECT* router,
|
||||
void* rsession,
|
||||
GWBUF* read_buf);
|
||||
|
||||
/*
|
||||
* The "module object" for the mysqld client protocol module.
|
||||
@ -73,7 +78,7 @@ static GWPROTOCOL MyObject = {
|
||||
gw_MySQLListener, /* Listen */
|
||||
NULL, /* Authentication */
|
||||
NULL /* Session */
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the mandatory version entry point
|
||||
@ -621,10 +626,11 @@ int gw_read_client_event(DCB* dcb) {
|
||||
*/
|
||||
{
|
||||
int len = -1;
|
||||
GWBUF *queue = NULL;
|
||||
GWBUF *gw_buffer = NULL;
|
||||
uint8_t cap = 0;
|
||||
GWBUF *read_buffer = NULL;
|
||||
uint8_t *ptr_buff = NULL;
|
||||
int mysql_command = -1;
|
||||
bool stmt_input; /*< router input type */
|
||||
|
||||
session = dcb->session;
|
||||
|
||||
@ -640,21 +646,20 @@ int gw_read_client_event(DCB* dcb) {
|
||||
//////////////////////////////////////////////////////
|
||||
// read and handle errors & close, or return if busy
|
||||
//////////////////////////////////////////////////////
|
||||
rc = gw_read_gwbuff(dcb, &gw_buffer, b);
|
||||
rc = gw_read_gwbuff(dcb, &read_buffer, b);
|
||||
|
||||
if (rc != 0) {
|
||||
goto return_rc;
|
||||
}
|
||||
/* Now, we are assuming in the first buffer there is
|
||||
* the information form mysql command */
|
||||
queue = gw_buffer;
|
||||
len = GWBUF_LENGTH(queue);
|
||||
ptr_buff = GWBUF_DATA(queue);
|
||||
len = GWBUF_LENGTH(read_buffer);
|
||||
ptr_buff = GWBUF_DATA(read_buffer);
|
||||
|
||||
/* get mysql commang at fifth byte */
|
||||
if (ptr_buff) {
|
||||
mysql_command = ptr_buff[4];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Without rsession there is no access to backend.
|
||||
* COM_QUIT : close client dcb
|
||||
@ -683,12 +688,38 @@ int gw_read_client_event(DCB* dcb) {
|
||||
}
|
||||
rc = 1;
|
||||
/** Free buffer */
|
||||
queue = gwbuf_consume(queue, len);
|
||||
read_buffer = gwbuf_consume(read_buffer, len);
|
||||
goto return_rc;
|
||||
}
|
||||
/** Ask what type of input the router expects */
|
||||
cap = router->getCapabilities(router_instance, rsession);
|
||||
|
||||
if (cap == 0 || (cap == RCAP_TYPE_PACKET_INPUT))
|
||||
{
|
||||
stmt_input = false;
|
||||
}
|
||||
else if (cap == RCAP_TYPE_STMT_INPUT)
|
||||
{
|
||||
stmt_input = true;
|
||||
/** Mark buffer to as MySQL type */
|
||||
gwbuf_set_type(read_buffer, GWBUF_TYPE_MYSQL);
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_send_custom_error(dcb,
|
||||
1,
|
||||
0,
|
||||
"Reading router capabilities "
|
||||
"failed. Router session is "
|
||||
"closed.");
|
||||
rc = 1;
|
||||
goto return_rc;
|
||||
}
|
||||
|
||||
|
||||
/** Route COM_QUIT to backend */
|
||||
if (mysql_command == '\x01') {
|
||||
router->routeQuery(router_instance, rsession, queue);
|
||||
router->routeQuery(router_instance, rsession, read_buffer);
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [gw_read_client_event] Routed COM_QUIT to "
|
||||
@ -704,10 +735,25 @@ int gw_read_client_event(DCB* dcb) {
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Route other commands to backend */
|
||||
rc = router->routeQuery(router_instance,
|
||||
if (stmt_input)
|
||||
{
|
||||
/**
|
||||
* Feed each statement completely and separately
|
||||
* to router.
|
||||
*/
|
||||
rc = route_by_statement(router_instance,
|
||||
router,
|
||||
rsession,
|
||||
read_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Feed whole packet to router */
|
||||
rc = router->routeQuery(router_instance,
|
||||
rsession,
|
||||
queue);
|
||||
read_buffer);
|
||||
}
|
||||
|
||||
/** succeed */
|
||||
if (rc == 1) {
|
||||
rc = 0; /**< here '0' means success */
|
||||
@ -1193,7 +1239,6 @@ static int gw_error_client_event(DCB *dcb) {
|
||||
router = session->service->router;
|
||||
router_instance = session->service->router_instance;
|
||||
rsession = session->router_session;
|
||||
|
||||
router->closeSession(router_instance, rsession);
|
||||
}
|
||||
dcb_close(dcb);
|
||||
@ -1251,7 +1296,8 @@ gw_client_hangup_event(DCB *dcb)
|
||||
void* router_instance;
|
||||
void* rsession;
|
||||
int rc = 1;
|
||||
#if defined(SS_DEBUG)
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol;
|
||||
if (dcb->state == DCB_STATE_POLLING ||
|
||||
dcb->state == DCB_STATE_NOPOLLING ||
|
||||
@ -1260,8 +1306,6 @@ gw_client_hangup_event(DCB *dcb)
|
||||
CHK_PROTOCOL(protocol);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
CHK_DCB(dcb);
|
||||
|
||||
if (dcb->state != DCB_STATE_POLLING) {
|
||||
@ -1278,7 +1322,6 @@ gw_client_hangup_event(DCB *dcb)
|
||||
router = session->service->router;
|
||||
router_instance = session->service->router_instance;
|
||||
rsession = session->router_session;
|
||||
|
||||
router->closeSession(router_instance, rsession);
|
||||
}
|
||||
|
||||
@ -1286,3 +1329,99 @@ gw_client_hangup_event(DCB *dcb)
|
||||
return_rc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect if buffer includes partial mysql packet or multiple packets.
|
||||
* Store partial packet to pendingqueue. Send complete packets one by one
|
||||
* to router.
|
||||
*/
|
||||
static int route_by_statement(
|
||||
ROUTER* router_instance,
|
||||
ROUTER_OBJECT* router,
|
||||
void* rsession,
|
||||
GWBUF* readbuf)
|
||||
{
|
||||
int rc = -1;
|
||||
DCB* master_dcb;
|
||||
GWBUF* stmtbuf;
|
||||
uint8_t* payload;
|
||||
static size_t len;
|
||||
|
||||
do
|
||||
{
|
||||
stmtbuf = gw_MySQL_get_next_stmt(&readbuf);
|
||||
ss_dassert(stmtbuf != NULL);
|
||||
CHK_GWBUF(stmtbuf);
|
||||
|
||||
payload = (uint8_t *)GWBUF_DATA(stmtbuf);
|
||||
/**
|
||||
* If message is longer than read data, suspend routing and
|
||||
* add statement buffer to wait queue.
|
||||
*/
|
||||
rc = router->routeQuery(router_instance, rsession, stmtbuf);
|
||||
}
|
||||
while (readbuf != NULL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a character array including the query string.
|
||||
* GWBUF given as input includes either one complete or partial query.
|
||||
* Length of buffer is at most the query length+4 (length of packet header).
|
||||
*/
|
||||
#if defined(NOT_USED)
|
||||
static char* gw_get_or_create_querystr (
|
||||
void* data,
|
||||
bool* new_allocation)
|
||||
{
|
||||
GWBUF* buf = (GWBUF *)data;
|
||||
size_t buflen; /*< first gw buffer data length */
|
||||
size_t packetlen; /*< length of mysql packet */
|
||||
size_t querylen; /*< total buffer length-<length of type indicator> */
|
||||
size_t nbytes_copied;
|
||||
char* startpos; /*< first byte of query in gw buffer */
|
||||
char* str; /*< resulting query string */
|
||||
|
||||
CHK_GWBUF(buf);
|
||||
packetlen = MYSQL_GET_PACKET_LEN((uint8_t *)GWBUF_DATA(buf));
|
||||
str = (char *)malloc(packetlen); /*< leave space for terminating null */
|
||||
|
||||
if (str == NULL)
|
||||
{
|
||||
goto return_str;
|
||||
}
|
||||
*new_allocation = true;
|
||||
/**
|
||||
* First buffer includes 4 bytes header and a type indicator byte.
|
||||
*/
|
||||
buflen = GWBUF_LENGTH(buf);
|
||||
querylen = packetlen-1;
|
||||
ss_dassert(buflen<=querylen+5); /*< 5 == header+type indicator */
|
||||
startpos = (char *)GWBUF_DATA(buf)+5;
|
||||
nbytes_copied = MIN(querylen, buflen-5);
|
||||
memcpy(str, startpos, nbytes_copied);
|
||||
memset(&str[querylen-1], 0, 1);
|
||||
buf = gwbuf_consume(buf, querylen-1);
|
||||
|
||||
/**
|
||||
* In case of multi-packet statement whole buffer consists of query
|
||||
* string.
|
||||
*/
|
||||
while (buf != NULL)
|
||||
{
|
||||
buflen = GWBUF_LENGTH(buf);
|
||||
memcpy(str+nbytes_copied, GWBUF_DATA(buf), buflen);
|
||||
nbytes_copied += buflen;
|
||||
buf = gwbuf_consume(buf, buflen);
|
||||
}
|
||||
ss_dassert(str[querylen-1] == 0);
|
||||
|
||||
return_str:
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -182,7 +182,7 @@ int gw_read_backend_handshake(MySQLProtocol *conn) {
|
||||
conn->state = MYSQL_AUTH_SENT;
|
||||
|
||||
// consume all the data here
|
||||
head = gwbuf_consume(head, gwbuf_length(head));
|
||||
head = gwbuf_consume(head, GWBUF_LENGTH(head));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -342,7 +342,7 @@ int gw_receive_backend_auth(
|
||||
/*<
|
||||
* Remove data from buffer.
|
||||
*/
|
||||
head = gwbuf_consume(head, gwbuf_length(head));
|
||||
head = gwbuf_consume(head, GWBUF_LENGTH(head));
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
@ -1280,3 +1280,57 @@ mysql_send_auth_error (DCB *dcb, int packet_number, int in_affected_rows, const
|
||||
|
||||
return sizeof(mysql_packet_header) + mysql_payload_size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the first mysql statement from buffer. Return pointer to the removed
|
||||
* statement or NULL if buffer is empty.
|
||||
*
|
||||
* Clone buf, calculate the length of included mysql stmt, and point the
|
||||
* statement with cloned buffer. Move the start pointer of buf accordingly
|
||||
* so that it only cover the remaining buffer.
|
||||
*
|
||||
*/
|
||||
GWBUF* gw_MySQL_get_next_stmt(
|
||||
GWBUF** p_readbuf)
|
||||
{
|
||||
GWBUF* stmtbuf;
|
||||
size_t buflen;
|
||||
size_t strlen;
|
||||
uint8_t* packet;
|
||||
|
||||
if (*p_readbuf == NULL)
|
||||
{
|
||||
stmtbuf = NULL;
|
||||
goto return_stmtbuf;
|
||||
}
|
||||
CHK_GWBUF(*p_readbuf);
|
||||
|
||||
if (GWBUF_EMPTY(*p_readbuf))
|
||||
{
|
||||
stmtbuf = NULL;
|
||||
goto return_stmtbuf;
|
||||
}
|
||||
buflen = GWBUF_LENGTH((*p_readbuf));
|
||||
packet = GWBUF_DATA((*p_readbuf));
|
||||
strlen = MYSQL_GET_PACKET_LEN(packet);
|
||||
|
||||
if (strlen+4 == buflen)
|
||||
{
|
||||
stmtbuf = *p_readbuf;
|
||||
*p_readbuf = NULL;
|
||||
goto return_stmtbuf;
|
||||
}
|
||||
/** vraa :Multi-packet stmt is not supported as of 7.3.14 */
|
||||
if (strlen-1 > buflen-5)
|
||||
{
|
||||
stmtbuf = NULL;
|
||||
goto return_stmtbuf;
|
||||
}
|
||||
stmtbuf = gwbuf_clone_portion(*p_readbuf, 0, strlen+4);
|
||||
*p_readbuf = gwbuf_consume(*p_readbuf, strlen+4);
|
||||
|
||||
return_stmtbuf:
|
||||
return stmtbuf;
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@ static void closeSession(ROUTER *instance, void *router_session);
|
||||
static void freeSession(ROUTER *instance, void *router_session);
|
||||
static int execute(ROUTER *instance, void *router_session, GWBUF *queue);
|
||||
static void diagnostics(ROUTER *instance, DCB *dcb);
|
||||
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||
|
||||
/** The module object definition */
|
||||
static ROUTER_OBJECT MyObject = {
|
||||
@ -64,7 +65,8 @@ static ROUTER_OBJECT MyObject = {
|
||||
execute,
|
||||
diagnostics,
|
||||
NULL,
|
||||
NULL
|
||||
NULL,
|
||||
getCapabilities
|
||||
};
|
||||
|
||||
extern int execute_cmd(CLI_SESSION *cli);
|
||||
@ -273,3 +275,10 @@ diagnostics(ROUTER *instance, DCB *dcb)
|
||||
{
|
||||
return; /* Nothing to do currently */
|
||||
}
|
||||
|
||||
static uint8_t getCapabilities(
|
||||
ROUTER* inst,
|
||||
void* router_session)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -108,6 +108,8 @@ static void errorReply(
|
||||
char *message,
|
||||
DCB *backend_dcb,
|
||||
int action);
|
||||
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||
|
||||
|
||||
/** The module object definition */
|
||||
static ROUTER_OBJECT MyObject = {
|
||||
@ -118,13 +120,14 @@ static ROUTER_OBJECT MyObject = {
|
||||
routeQuery,
|
||||
diagnostics,
|
||||
clientReply,
|
||||
errorReply
|
||||
errorReply,
|
||||
getCapabilities
|
||||
};
|
||||
|
||||
static bool rses_begin_router_action(
|
||||
static bool rses_begin_locked_router_action(
|
||||
ROUTER_CLIENT_SES* rses);
|
||||
|
||||
static void rses_exit_router_action(
|
||||
static void rses_end_locked_router_action(
|
||||
ROUTER_CLIENT_SES* rses);
|
||||
|
||||
static SPINLOCK instlock;
|
||||
@ -399,6 +402,8 @@ int master_host = -1;
|
||||
}
|
||||
}
|
||||
|
||||
client_rses->rses_capabilities = RCAP_TYPE_PACKET_INPUT;
|
||||
|
||||
/*
|
||||
* We now have the server with the least connections.
|
||||
* Bump the connection count for this server
|
||||
@ -517,7 +522,7 @@ DCB* backend_dcb;
|
||||
/**
|
||||
* Lock router client session for secure read and update.
|
||||
*/
|
||||
if (rses_begin_router_action(router_cli_ses))
|
||||
if (rses_begin_locked_router_action(router_cli_ses))
|
||||
{
|
||||
/* decrease server current connection counter */
|
||||
atomic_add(&router_cli_ses->backend->server->stats.n_current, -1);
|
||||
@ -526,7 +531,7 @@ DCB* backend_dcb;
|
||||
router_cli_ses->backend_dcb = NULL;
|
||||
router_cli_ses->rses_closed = true;
|
||||
/** Unlock */
|
||||
rses_exit_router_action(router_cli_ses);
|
||||
rses_end_locked_router_action(router_cli_ses);
|
||||
|
||||
/**
|
||||
* Close the backend server connection
|
||||
@ -572,14 +577,14 @@ routeQuery(ROUTER *instance, void *router_session, GWBUF *queue)
|
||||
/**
|
||||
* Lock router client session for secure read of DCBs
|
||||
*/
|
||||
rses_is_closed = !(rses_begin_router_action(router_cli_ses));
|
||||
rses_is_closed = !(rses_begin_locked_router_action(router_cli_ses));
|
||||
}
|
||||
|
||||
if (!rses_is_closed)
|
||||
{
|
||||
backend_dcb = router_cli_ses->backend_dcb;
|
||||
/** unlock */
|
||||
rses_exit_router_action(router_cli_ses);
|
||||
rses_end_locked_router_action(router_cli_ses);
|
||||
}
|
||||
|
||||
if (rses_is_closed || backend_dcb == NULL)
|
||||
@ -690,7 +695,7 @@ static void
|
||||
errorReply(
|
||||
ROUTER *instance,
|
||||
void *router_session,
|
||||
char *message,
|
||||
char *message,
|
||||
DCB *backend_dcb,
|
||||
int action)
|
||||
{
|
||||
@ -717,7 +722,7 @@ errorReply(
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
static bool rses_begin_router_action(
|
||||
static bool rses_begin_locked_router_action(
|
||||
ROUTER_CLIENT_SES* rses)
|
||||
{
|
||||
bool succp = false;
|
||||
@ -752,9 +757,17 @@ return_succp:
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
static void rses_exit_router_action(
|
||||
static void rses_end_locked_router_action(
|
||||
ROUTER_CLIENT_SES* rses)
|
||||
{
|
||||
CHK_CLIENT_RSES(rses);
|
||||
spinlock_release(&rses->rses_lock);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t getCapabilities(
|
||||
ROUTER* inst,
|
||||
void* router_session)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@ static void closeSession(ROUTER *instance, void *session);
|
||||
static void freeSession(ROUTER *instance, void *session);
|
||||
static int routeQuery(ROUTER *instance, void *session, GWBUF *queue);
|
||||
static void diagnostic(ROUTER *instance, DCB *dcb);
|
||||
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||
|
||||
|
||||
static ROUTER_OBJECT MyObject = {
|
||||
@ -36,7 +37,8 @@ static ROUTER_OBJECT MyObject = {
|
||||
routeQuery,
|
||||
diagnostic,
|
||||
NULL,
|
||||
NULL
|
||||
NULL,
|
||||
getCapabilities
|
||||
};
|
||||
|
||||
/**
|
||||
@ -137,3 +139,10 @@ static void
|
||||
diagnostic(ROUTER *instance, DCB *dcb)
|
||||
{
|
||||
}
|
||||
|
||||
static uint8_t getCapabilities(
|
||||
ROUTER* inst,
|
||||
void* router_session)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -117,7 +117,9 @@ typedef enum skygw_chk_t {
|
||||
CHK_NUM_DCB,
|
||||
CHK_NUM_PROTOCOL,
|
||||
CHK_NUM_SESSION,
|
||||
CHK_NUM_ROUTER_SES
|
||||
CHK_NUM_ROUTER_SES,
|
||||
CHK_NUM_MY_SESCMD,
|
||||
CHK_NUM_ROUTER_PROPERTY
|
||||
} skygw_chk_t;
|
||||
|
||||
# define STRBOOL(b) ((b) ? "true" : "false")
|
||||
@ -214,7 +216,11 @@ typedef enum skygw_chk_t {
|
||||
((r) == DCB_ROLE_REQUEST_HANDLER ? "DCB_ROLE_REQUEST_HANDLER" : \
|
||||
"UNKNOWN DCB ROLE"))
|
||||
|
||||
|
||||
#define STRBETYPE(t) ((t) == BE_MASTER ? "BE_MASTER" : \
|
||||
((t) == BE_SLAVE ? "BE_SLAVE" : \
|
||||
((t) == BE_UNDEFINED ? "BE_UNDEFINED" : \
|
||||
"Unknown backend tpe")))
|
||||
|
||||
#define CHK_MLIST(l) { \
|
||||
ss_info_dassert((l->mlist_chk_top == CHK_NUM_MLIST && \
|
||||
l->mlist_chk_tail == CHK_NUM_MLIST), \
|
||||
@ -428,7 +434,19 @@ typedef enum skygw_chk_t {
|
||||
"Router client session has invalid check fields"); \
|
||||
}
|
||||
|
||||
|
||||
#define CHK_RSES_PROP(p) { \
|
||||
ss_info_dassert((p)->rses_prop_chk_top == CHK_NUM_ROUTER_PROPERTY && \
|
||||
(p)->rses_prop_chk_tail == CHK_NUM_ROUTER_PROPERTY, \
|
||||
"Router property has invalid check fields"); \
|
||||
}
|
||||
|
||||
#define CHK_MYSQL_SESCMD(s) { \
|
||||
ss_info_dassert((s)->my_sescmd_chk_top == CHK_NUM_MY_SESCMD && \
|
||||
(s)->my_sescmd_chk_tail == CHK_NUM_MY_SESCMD, \
|
||||
"Session command has invalid check fields"); \
|
||||
}
|
||||
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
bool conn_open[10240];
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user