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:
@ -81,6 +81,7 @@ SHARED_BUF *sbuf;
|
|||||||
sbuf->refcount = 1;
|
sbuf->refcount = 1;
|
||||||
rval->sbuf = sbuf;
|
rval->sbuf = sbuf;
|
||||||
rval->next = NULL;
|
rval->next = NULL;
|
||||||
|
rval->gwbuf_type = GWBUF_TYPE_UNDEFINED;
|
||||||
rval->command = 0;
|
rval->command = 0;
|
||||||
CHK_GWBUF(rval);
|
CHK_GWBUF(rval);
|
||||||
return rval;
|
return rval;
|
||||||
@ -127,11 +128,93 @@ GWBUF *rval;
|
|||||||
rval->sbuf = buf->sbuf;
|
rval->sbuf = buf->sbuf;
|
||||||
rval->start = buf->start;
|
rval->start = buf->start;
|
||||||
rval->end = buf->end;
|
rval->end = buf->end;
|
||||||
|
rval->gwbuf_type = buf->gwbuf_type;
|
||||||
rval->next = NULL;
|
rval->next = NULL;
|
||||||
rval->command = buf->command;
|
|
||||||
CHK_GWBUF(rval);
|
CHK_GWBUF(rval);
|
||||||
return 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.
|
* Append a buffer onto a linked list of buffer structures.
|
||||||
*
|
*
|
||||||
@ -150,6 +233,7 @@ GWBUF *ptr = head;
|
|||||||
if (!head)
|
if (!head)
|
||||||
return tail;
|
return tail;
|
||||||
CHK_GWBUF(head);
|
CHK_GWBUF(head);
|
||||||
|
CHK_GWBUF(tail);
|
||||||
while (ptr->next)
|
while (ptr->next)
|
||||||
{
|
{
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
@ -178,9 +262,10 @@ GWBUF *
|
|||||||
gwbuf_consume(GWBUF *head, unsigned int length)
|
gwbuf_consume(GWBUF *head, unsigned int length)
|
||||||
{
|
{
|
||||||
GWBUF *rval = head;
|
GWBUF *rval = head;
|
||||||
|
|
||||||
CHK_GWBUF(head);
|
CHK_GWBUF(head);
|
||||||
GWBUF_CONSUME(head, length);
|
GWBUF_CONSUME(head, length);
|
||||||
|
CHK_GWBUF(head);
|
||||||
|
|
||||||
if (GWBUF_EMPTY(head))
|
if (GWBUF_EMPTY(head))
|
||||||
{
|
{
|
||||||
rval = head->next;
|
rval = head->next;
|
||||||
@ -207,3 +292,28 @@ int rval = 0;
|
|||||||
}
|
}
|
||||||
return rval;
|
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)
|
if (dcb->remote)
|
||||||
free(dcb->remote);
|
free(dcb->remote);
|
||||||
bitmask_free(&dcb->memdata.bitmask);
|
bitmask_free(&dcb->memdata.bitmask);
|
||||||
|
|
||||||
#if 1
|
|
||||||
simple_mutex_done(&dcb->dcb_read_lock);
|
simple_mutex_done(&dcb->dcb_read_lock);
|
||||||
simple_mutex_done(&dcb->dcb_write_lock);
|
simple_mutex_done(&dcb->dcb_write_lock);
|
||||||
#endif
|
|
||||||
|
|
||||||
free(dcb);
|
free(dcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,6 +523,8 @@ int rc;
|
|||||||
* Successfully connected to backend. Assign file descriptor to dcb
|
* Successfully connected to backend. Assign file descriptor to dcb
|
||||||
*/
|
*/
|
||||||
dcb->fd = fd;
|
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
|
* 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_LISTENING &&
|
||||||
dcb->state != DCB_STATE_NOPOLLING))
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
spinlock_acquire(&dcb->writeqlock);
|
spinlock_acquire(&dcb->writeqlock);
|
||||||
|
|
||||||
if (dcb->writeq != NULL)
|
if (dcb->writeq != NULL)
|
||||||
@ -750,7 +756,11 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
#endif /* SS_DEBUG */
|
#endif /* SS_DEBUG */
|
||||||
len = GWBUF_LENGTH(queue);
|
len = GWBUF_LENGTH(queue);
|
||||||
GW_NOINTR_CALL(
|
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++;
|
dcb->stats.n_writes++;
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -759,6 +769,8 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
|
if (LOG_IS_ENABLED(LOGFILE_DEBUG))
|
||||||
|
{
|
||||||
if (saved_errno == EPIPE) {
|
if (saved_errno == EPIPE) {
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
@ -771,7 +783,12 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
dcb->fd,
|
dcb->fd,
|
||||||
saved_errno,
|
saved_errno,
|
||||||
strerror(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)
|
saved_errno != EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
@ -785,6 +802,7 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
saved_errno,
|
saved_errno,
|
||||||
strerror(saved_errno))));
|
strerror(saved_errno))));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -799,9 +817,9 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
pthread_self(),
|
pthread_self(),
|
||||||
w,
|
w,
|
||||||
dcb,
|
dcb,
|
||||||
STRDCBSTATE(dcb->state),
|
STRDCBSTATE(dcb->state),
|
||||||
dcb->fd)));
|
dcb->fd)));
|
||||||
}
|
} /*< while (queue != NULL) */
|
||||||
/*<
|
/*<
|
||||||
* What wasn't successfully written is stored to write queue
|
* What wasn't successfully written is stored to write queue
|
||||||
* for suspended write.
|
* for suspended write.
|
||||||
@ -819,7 +837,6 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
saved_errno != EAGAIN &&
|
saved_errno != EAGAIN &&
|
||||||
saved_errno != EWOULDBLOCK)
|
saved_errno != EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
queue = gwbuf_consume(queue, gwbuf_length(queue));
|
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
LOGFILE_ERROR,
|
LOGFILE_ERROR,
|
||||||
"Error : Writing to %s socket failed due %d, %s.",
|
"Error : Writing to %s socket failed due %d, %s.",
|
||||||
@ -862,9 +879,13 @@ int saved_errno = 0;
|
|||||||
while (dcb->writeq != NULL)
|
while (dcb->writeq != NULL)
|
||||||
{
|
{
|
||||||
len = GWBUF_LENGTH(dcb->writeq);
|
len = GWBUF_LENGTH(dcb->writeq);
|
||||||
GW_NOINTR_CALL(w = gw_write(dcb->fd,
|
GW_NOINTR_CALL(w = gw_write(
|
||||||
GWBUF_DATA(dcb->writeq),
|
#if defined(SS_DEBUG)
|
||||||
len););
|
dcb,
|
||||||
|
#endif
|
||||||
|
dcb->fd,
|
||||||
|
GWBUF_DATA(dcb->writeq),
|
||||||
|
len););
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
@ -1319,12 +1340,15 @@ static bool dcb_set_state_nomutex(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int gw_write(
|
int gw_write(
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
|
DCB* dcb,
|
||||||
|
#endif
|
||||||
int fd,
|
int fd,
|
||||||
const void* buf,
|
const void* buf,
|
||||||
size_t nbytes)
|
size_t nbytes)
|
||||||
{
|
{
|
||||||
int w;
|
int w;
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
if (dcb_fake_write_errno[fd] != 0) {
|
if (dcb_fake_write_errno[fd] != 0) {
|
||||||
ss_dassert(dcb_fake_write_ev[fd] != 0);
|
ss_dassert(dcb_fake_write_ev[fd] != 0);
|
||||||
w = write(fd, buf, nbytes/2); /*< leave peer to read missing bytes */
|
w = write(fd, buf, nbytes/2); /*< leave peer to read missing bytes */
|
||||||
@ -1339,6 +1363,57 @@ int gw_write(
|
|||||||
#else
|
#else
|
||||||
w = write(fd, buf, nbytes);
|
w = write(fd, buf, nbytes);
|
||||||
#endif /* SS_DEBUG && SS_TEST */
|
#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;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -363,7 +363,6 @@ poll_waitevents(void *arg)
|
|||||||
eno = gw_getsockerrno(dcb->fd);
|
eno = gw_getsockerrno(dcb->fd);
|
||||||
|
|
||||||
if (eno == 0) {
|
if (eno == 0) {
|
||||||
#if 1
|
|
||||||
simple_mutex_lock(
|
simple_mutex_lock(
|
||||||
&dcb->dcb_write_lock,
|
&dcb->dcb_write_lock,
|
||||||
true);
|
true);
|
||||||
@ -371,16 +370,13 @@ poll_waitevents(void *arg)
|
|||||||
!dcb->dcb_write_active,
|
!dcb->dcb_write_active,
|
||||||
"Write already active");
|
"Write already active");
|
||||||
dcb->dcb_write_active = TRUE;
|
dcb->dcb_write_active = TRUE;
|
||||||
#endif
|
|
||||||
atomic_add(
|
atomic_add(
|
||||||
&pollStats.n_write,
|
&pollStats.n_write,
|
||||||
1);
|
1);
|
||||||
dcb->func.write_ready(dcb);
|
dcb->func.write_ready(dcb);
|
||||||
#if 1
|
|
||||||
dcb->dcb_write_active = FALSE;
|
dcb->dcb_write_active = FALSE;
|
||||||
simple_mutex_unlock(
|
simple_mutex_unlock(
|
||||||
&dcb->dcb_write_lock);
|
&dcb->dcb_write_lock);
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
@ -396,13 +392,12 @@ poll_waitevents(void *arg)
|
|||||||
}
|
}
|
||||||
if (ev & EPOLLIN)
|
if (ev & EPOLLIN)
|
||||||
{
|
{
|
||||||
#if 1
|
|
||||||
simple_mutex_lock(&dcb->dcb_read_lock,
|
simple_mutex_lock(&dcb->dcb_read_lock,
|
||||||
true);
|
true);
|
||||||
ss_info_dassert(!dcb->dcb_read_active,
|
ss_info_dassert(!dcb->dcb_read_active,
|
||||||
"Read already active");
|
"Read already active");
|
||||||
dcb->dcb_read_active = TRUE;
|
dcb->dcb_read_active = TRUE;
|
||||||
#endif
|
|
||||||
if (dcb->state == DCB_STATE_LISTENING)
|
if (dcb->state == DCB_STATE_LISTENING)
|
||||||
{
|
{
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
@ -427,11 +422,9 @@ poll_waitevents(void *arg)
|
|||||||
atomic_add(&pollStats.n_read, 1);
|
atomic_add(&pollStats.n_read, 1);
|
||||||
dcb->func.read(dcb);
|
dcb->func.read(dcb);
|
||||||
}
|
}
|
||||||
#if 1
|
|
||||||
dcb->dcb_read_active = FALSE;
|
dcb->dcb_read_active = FALSE;
|
||||||
simple_mutex_unlock(
|
simple_mutex_unlock(
|
||||||
&dcb->dcb_read_lock);
|
&dcb->dcb_read_lock);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (ev & EPOLLERR)
|
if (ev & EPOLLERR)
|
||||||
{
|
{
|
||||||
@ -462,6 +455,7 @@ poll_waitevents(void *arg)
|
|||||||
atomic_add(&pollStats.n_error, 1);
|
atomic_add(&pollStats.n_error, 1);
|
||||||
dcb->func.error(dcb);
|
dcb->func.error(dcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev & EPOLLHUP)
|
if (ev & EPOLLHUP)
|
||||||
{
|
{
|
||||||
int eno = 0;
|
int eno = 0;
|
||||||
|
|||||||
@ -41,9 +41,18 @@
|
|||||||
*
|
*
|
||||||
* @endverbatim
|
* @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
|
* shared between multiple GWBUF's without the need to make multiple copies
|
||||||
* but still maintain separate data pointers.
|
* but still maintain separate data pointers.
|
||||||
*/
|
*/
|
||||||
@ -64,8 +73,9 @@ typedef struct gwbuf {
|
|||||||
struct gwbuf *next; /*< Next buffer in a linked chain of buffers */
|
struct gwbuf *next; /*< Next buffer in a linked chain of buffers */
|
||||||
void *start; /*< Start of the valid data */
|
void *start; /*< Start of the valid data */
|
||||||
void *end; /*< First byte after 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 */
|
int command;/*< The command type for the queue */
|
||||||
|
gwbuf_type_t gwbuf_type; /*< buffer's data type information */
|
||||||
} GWBUF;
|
} GWBUF;
|
||||||
|
|
||||||
/*<
|
/*<
|
||||||
@ -83,6 +93,7 @@ typedef struct gwbuf {
|
|||||||
/*< Consume a number of bytes in the buffer */
|
/*< Consume a number of bytes in the buffer */
|
||||||
#define GWBUF_CONSUME(b, bytes) (b)->start += bytes
|
#define GWBUF_CONSUME(b, bytes) (b)->start += bytes
|
||||||
|
|
||||||
|
#define GWBUF_TYPE(b) (b)->gwbuf_type
|
||||||
/*<
|
/*<
|
||||||
* Function prototypes for the API to maniplate the buffers
|
* 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_append(GWBUF *head, GWBUF *tail);
|
||||||
extern GWBUF *gwbuf_consume(GWBUF *head, unsigned int length);
|
extern GWBUF *gwbuf_consume(GWBUF *head, unsigned int length);
|
||||||
extern unsigned int gwbuf_length(GWBUF *head);
|
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
|
#endif
|
||||||
|
|||||||
@ -179,7 +179,7 @@ typedef struct dcb {
|
|||||||
SPINLOCK authlock; /**< Generic Authorization spinlock */
|
SPINLOCK authlock; /**< Generic Authorization spinlock */
|
||||||
|
|
||||||
DCBSTATS stats; /**< DCB related statistics */
|
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 dcb *next; /**< Next DCB in the chain of allocated DCB's */
|
||||||
struct service *service; /**< The related service */
|
struct service *service; /**< The related service */
|
||||||
void *data; /**< Specific client data */
|
void *data; /**< Specific client data */
|
||||||
@ -205,7 +205,13 @@ int fail_accept_errno;
|
|||||||
#define DCB_ISZOMBIE(x) ((x)->state == DCB_STATE_ZOMBIE)
|
#define DCB_ISZOMBIE(x) ((x)->state == DCB_STATE_ZOMBIE)
|
||||||
|
|
||||||
DCB *dcb_get_zombies(void);
|
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 *);
|
int dcb_write(DCB *, GWBUF *);
|
||||||
DCB *dcb_alloc(dcb_role_t);
|
DCB *dcb_alloc(dcb_role_t);
|
||||||
void dcb_free(DCB *);
|
void dcb_free(DCB *);
|
||||||
|
|||||||
@ -54,6 +54,12 @@ int do_read_dcb(DCB *dcb);
|
|||||||
int do_read_10(DCB *dcb, uint8_t *buffer);
|
int do_read_10(DCB *dcb, uint8_t *buffer);
|
||||||
int MySQLWrite(DCB *dcb, GWBUF *queue);
|
int MySQLWrite(DCB *dcb, GWBUF *queue);
|
||||||
int setnonblocking(int fd);
|
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 gw_getsockerrno(int fd);
|
||||||
int parse_bindconfig(char *, unsigned short, struct sockaddr_in *);
|
int parse_bindconfig(char *, unsigned short, struct sockaddr_in *);
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
#include <service.h>
|
#include <service.h>
|
||||||
#include <session.h>
|
#include <session.h>
|
||||||
#include <buffer.h>
|
#include <buffer.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ROUTER handle points to module specific data, so the best we can do
|
* 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 (*diagnostics)(ROUTER *instance, DCB *dcb);
|
||||||
void (*clientReply)(ROUTER* instance, void* router_session, GWBUF* queue, DCB *backend_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);
|
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_OBJECT;
|
||||||
|
|
||||||
/* Router commands */
|
typedef enum router_capability_t {
|
||||||
#define ROUTER_DEFAULT 0 /**< Standard routing */
|
RCAP_TYPE_UNDEFINED = 0,
|
||||||
#define ROUTER_CHANGE_SESSION 1 /**< Route a change session */
|
RCAP_TYPE_STMT_INPUT = (1 << 0),
|
||||||
|
RCAP_TYPE_PACKET_INPUT = (1 << 1)
|
||||||
|
} router_capability_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -53,6 +53,8 @@ typedef struct spinlock {
|
|||||||
#define SPINLOCK_INIT { 0 }
|
#define SPINLOCK_INIT { 0 }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SPINLOCK_IS_LOCKED(l) ((l)->lock != 0 ? true : false)
|
||||||
|
|
||||||
extern void spinlock_init(SPINLOCK *lock);
|
extern void spinlock_init(SPINLOCK *lock);
|
||||||
extern void spinlock_acquire(SPINLOCK *lock);
|
extern void spinlock_acquire(SPINLOCK *lock);
|
||||||
extern int spinlock_acquire_nowait(SPINLOCK *lock);
|
extern int spinlock_acquire_nowait(SPINLOCK *lock);
|
||||||
|
|||||||
@ -297,6 +297,7 @@ void gw_str_xor(
|
|||||||
const uint8_t *input1,
|
const uint8_t *input1,
|
||||||
const uint8_t *input2,
|
const uint8_t *input2,
|
||||||
unsigned int len);
|
unsigned int len);
|
||||||
|
<<<<<<< HEAD
|
||||||
char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len);
|
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_hex2bin(uint8_t *out, const char *in, unsigned int len);
|
||||||
int gw_generate_random_str(char *output, 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 setnonblocking(int fd);
|
||||||
int setipaddress(struct in_addr *a, char *p);
|
int setipaddress(struct in_addr *a, char *p);
|
||||||
int gw_read_gwbuff(DCB *dcb, GWBUF **head, int b);
|
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 */
|
bool rses_closed; /*< true when closeSession is called */
|
||||||
BACKEND *backend; /*< Backend used by the client session */
|
BACKEND *backend; /*< Backend used by the client session */
|
||||||
DCB *backend_dcb; /*< DCB Connection to the backend */
|
DCB *backend_dcb; /*< DCB Connection to the backend */
|
||||||
struct router_client_session
|
struct router_client_session *next;
|
||||||
*next;
|
int rses_capabilities; /*< input type, for example */
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
skygw_chk_t rses_chk_tail;
|
skygw_chk_t rses_chk_tail;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
* @verbatim
|
* @verbatim
|
||||||
* Revision History
|
* Revision History
|
||||||
*
|
*
|
||||||
* bazaar..
|
* See GitHub https://github.com/skysql/MaxScale
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -41,25 +41,91 @@ typedef struct backend {
|
|||||||
int backend_conn_count; /*< Number of connections to the server */
|
int backend_conn_count; /*< Number of connections to the server */
|
||||||
} BACKEND;
|
} 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.
|
* The client session structure used within this router.
|
||||||
*/
|
*/
|
||||||
typedef struct router_client_session {
|
struct router_client_session {
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
skygw_chk_t rses_chk_top;
|
skygw_chk_t rses_chk_top;
|
||||||
#endif
|
#endif
|
||||||
SPINLOCK rses_lock; /*< protects rses_deleted */
|
SPINLOCK rses_lock; /*< protects rses_deleted */
|
||||||
int rses_versno; /*< even = no active update, else odd */
|
int rses_versno; /*< even = no active update, else odd */
|
||||||
bool rses_closed; /*< true when closeSession is called */
|
bool rses_closed; /*< true when closeSession is called */
|
||||||
BACKEND* be_slave; /*< Slave backend used by client session */
|
/** Properties listed by their type */
|
||||||
BACKEND* be_master; /*< Master backend used by client session */
|
rses_property_t* rses_properties[RSES_PROP_TYPE_COUNT];
|
||||||
DCB* slave_dcb; /*< Slave connection */
|
BACKEND* rses_backend[BE_COUNT];/*< Backends used by client session */
|
||||||
DCB* master_dcb; /*< Master connection */
|
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;
|
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;
|
||||||
#endif
|
#endif
|
||||||
} ROUTER_CLIENT_SES;
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The statistics for this router instance
|
* The statistics for this router instance
|
||||||
@ -88,5 +154,4 @@ typedef struct router_instance {
|
|||||||
struct router_instance* next; /*< Next router on the list */
|
struct router_instance* next; /*< Next router on the list */
|
||||||
} ROUTER_INSTANCE;
|
} ROUTER_INSTANCE;
|
||||||
|
|
||||||
|
#endif /*< _RWSPLITROUTER_H */
|
||||||
#endif
|
|
||||||
|
|||||||
@ -283,6 +283,8 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (backend_protocol->state == MYSQL_AUTH_FAILED) {
|
if (backend_protocol->state == MYSQL_AUTH_FAILED) {
|
||||||
|
|
||||||
|
spinlock_acquire(&dcb->delayqlock);
|
||||||
/*<
|
/*<
|
||||||
* vraa : errorHandle
|
* vraa : errorHandle
|
||||||
* check the delayq before the reply
|
* check the delayq before the reply
|
||||||
@ -295,10 +297,12 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
0,
|
0,
|
||||||
"Connection to backend lost.");
|
"Connection to backend lost.");
|
||||||
// consume all the delay queue
|
// consume all the delay queue
|
||||||
dcb->delayq = gwbuf_consume(
|
while ((dcb->delayq = gwbuf_consume(
|
||||||
dcb->delayq,
|
dcb->delayq,
|
||||||
gwbuf_length(dcb->delayq));
|
GWBUF_LENGTH(dcb->delayq))) != NULL);
|
||||||
}
|
}
|
||||||
|
spinlock_release(&dcb->delayqlock);
|
||||||
|
|
||||||
|
|
||||||
/* try reload users' table for next connection */
|
/* try reload users' table for next connection */
|
||||||
service_refresh_users(dcb->session->client->service);
|
service_refresh_users(dcb->session->client->service);
|
||||||
@ -350,7 +354,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
pthread_self(),
|
pthread_self(),
|
||||||
dcb->fd,
|
dcb->fd,
|
||||||
current_session->user)));
|
current_session->user)));
|
||||||
|
|
||||||
/* check the delay queue and flush the data */
|
/* check the delay queue and flush the data */
|
||||||
if (dcb->delayq)
|
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.
|
* 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) {
|
if (dcb->state != DCB_STATE_POLLING) {
|
||||||
/*< vraa : errorHandle */
|
/*< vraa : errorHandle */
|
||||||
/*< Free buffer memory */
|
/*< Free buffer memory */
|
||||||
@ -539,10 +543,12 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
|||||||
dcb->fd,
|
dcb->fd,
|
||||||
STRDCBSTATE(dcb->state))));
|
STRDCBSTATE(dcb->state))));
|
||||||
|
|
||||||
spinlock_release(&dcb->authlock);
|
spinlock_release(&dcb->dcb_initlock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
spinlock_release(&dcb->dcb_initlock);
|
||||||
|
|
||||||
|
spinlock_acquire(&dcb->authlock);
|
||||||
/*<
|
/*<
|
||||||
* Now put the incoming data to the delay queue unless backend is
|
* Now put the incoming data to the delay queue unless backend is
|
||||||
* connected with auth ok
|
* connected with auth ok
|
||||||
@ -556,7 +562,6 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
|||||||
dcb,
|
dcb,
|
||||||
dcb->fd,
|
dcb->fd,
|
||||||
STRPROTOCOLSTATE(backend_protocol->state))));
|
STRPROTOCOLSTATE(backend_protocol->state))));
|
||||||
|
|
||||||
backend_set_delayqueue(dcb, queue);
|
backend_set_delayqueue(dcb, queue);
|
||||||
spinlock_release(&dcb->authlock);
|
spinlock_release(&dcb->authlock);
|
||||||
return 1;
|
return 1;
|
||||||
@ -565,8 +570,6 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
|||||||
/*<
|
/*<
|
||||||
* Now we set the last command received, from the current queue
|
* Now we set the last command received, from the current queue
|
||||||
*/
|
*/
|
||||||
memcpy(&dcb->command, &queue->command, sizeof(dcb->command));
|
|
||||||
|
|
||||||
spinlock_release(&dcb->authlock);
|
spinlock_release(&dcb->authlock);
|
||||||
rc = dcb_write(dcb, queue);
|
rc = dcb_write(dcb, queue);
|
||||||
return rc;
|
return rc;
|
||||||
@ -804,12 +807,6 @@ static int backend_write_delayqueue(DCB *dcb)
|
|||||||
localq = dcb->delayq;
|
localq = dcb->delayq;
|
||||||
dcb->delayq = NULL;
|
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);
|
spinlock_release(&dcb->delayqlock);
|
||||||
rc = dcb_write(dcb, localq);
|
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;
|
unsigned int auth_token_len = 0;
|
||||||
uint8_t *auth_token = NULL;
|
uint8_t *auth_token = NULL;
|
||||||
int rv = -1;
|
int rv = -1;
|
||||||
int len = 0;
|
|
||||||
int auth_ret = 1;
|
int auth_ret = 1;
|
||||||
|
|
||||||
current_session = (MYSQL_session *)in_session->client->data;
|
current_session = (MYSQL_session *)in_session->client->data;
|
||||||
backend_protocol = backend->protocol;
|
backend_protocol = backend->protocol;
|
||||||
client_protocol = in_session->client->protocol;
|
client_protocol = in_session->client->protocol;
|
||||||
|
|
||||||
queue->command = ROUTER_CHANGE_SESSION;
|
|
||||||
|
|
||||||
// now get the user, after 4 bytes header and 1 byte command
|
// now get the user, after 4 bytes header and 1 byte command
|
||||||
client_auth_packet += 5;
|
client_auth_packet += 5;
|
||||||
strcpy(username, (char *)client_auth_packet);
|
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);
|
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
|
* Now copy new data into user session
|
||||||
*/
|
*/
|
||||||
strcpy(current_session->user, username);
|
strcpy(current_session->user, username);
|
||||||
strcpy(current_session->db, database);
|
strcpy(current_session->db, database);
|
||||||
memcpy(current_session->client_sha1, client_sha1, sizeof(current_session->client_sha1));
|
memcpy(current_session->client_sha1, client_sha1, sizeof(current_session->client_sha1));
|
||||||
|
}
|
||||||
}
|
gwbuf_free(queue);
|
||||||
|
|
||||||
// consume all the data received from client
|
|
||||||
|
|
||||||
spinlock_acquire(&backend->writeqlock);
|
|
||||||
|
|
||||||
len = gwbuf_length(queue);
|
|
||||||
queue = gwbuf_consume(queue, len);
|
|
||||||
|
|
||||||
spinlock_release(&backend->writeqlock);
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -951,7 +928,6 @@ static int gw_session(DCB *backend_dcb, void *data) {
|
|||||||
GWBUF *queue = NULL;
|
GWBUF *queue = NULL;
|
||||||
|
|
||||||
queue = (GWBUF *) data;
|
queue = (GWBUF *) data;
|
||||||
queue->command = ROUTER_CHANGE_SESSION;
|
|
||||||
backend_dcb->func.write(backend_dcb, queue);
|
backend_dcb->func.write(backend_dcb, queue);
|
||||||
|
|
||||||
return 1;
|
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 mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
|
||||||
int MySQLSendHandshake(DCB* dcb);
|
int MySQLSendHandshake(DCB* dcb);
|
||||||
static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue);
|
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.
|
* The "module object" for the mysqld client protocol module.
|
||||||
@ -73,7 +78,7 @@ static GWPROTOCOL MyObject = {
|
|||||||
gw_MySQLListener, /* Listen */
|
gw_MySQLListener, /* Listen */
|
||||||
NULL, /* Authentication */
|
NULL, /* Authentication */
|
||||||
NULL /* Session */
|
NULL /* Session */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the mandatory version entry point
|
* Implementation of the mandatory version entry point
|
||||||
@ -621,10 +626,11 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int len = -1;
|
int len = -1;
|
||||||
GWBUF *queue = NULL;
|
uint8_t cap = 0;
|
||||||
GWBUF *gw_buffer = NULL;
|
GWBUF *read_buffer = NULL;
|
||||||
uint8_t *ptr_buff = NULL;
|
uint8_t *ptr_buff = NULL;
|
||||||
int mysql_command = -1;
|
int mysql_command = -1;
|
||||||
|
bool stmt_input; /*< router input type */
|
||||||
|
|
||||||
session = dcb->session;
|
session = dcb->session;
|
||||||
|
|
||||||
@ -640,21 +646,20 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
// read and handle errors & close, or return if busy
|
// 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) {
|
if (rc != 0) {
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
}
|
||||||
/* Now, we are assuming in the first buffer there is
|
/* Now, we are assuming in the first buffer there is
|
||||||
* the information form mysql command */
|
* the information form mysql command */
|
||||||
queue = gw_buffer;
|
len = GWBUF_LENGTH(read_buffer);
|
||||||
len = GWBUF_LENGTH(queue);
|
ptr_buff = GWBUF_DATA(read_buffer);
|
||||||
ptr_buff = GWBUF_DATA(queue);
|
|
||||||
|
|
||||||
/* get mysql commang at fifth byte */
|
/* get mysql commang at fifth byte */
|
||||||
if (ptr_buff) {
|
if (ptr_buff) {
|
||||||
mysql_command = ptr_buff[4];
|
mysql_command = ptr_buff[4];
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Without rsession there is no access to backend.
|
* Without rsession there is no access to backend.
|
||||||
* COM_QUIT : close client dcb
|
* COM_QUIT : close client dcb
|
||||||
@ -683,12 +688,38 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
}
|
}
|
||||||
rc = 1;
|
rc = 1;
|
||||||
/** Free buffer */
|
/** Free buffer */
|
||||||
queue = gwbuf_consume(queue, len);
|
read_buffer = gwbuf_consume(read_buffer, len);
|
||||||
goto return_rc;
|
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 */
|
/** Route COM_QUIT to backend */
|
||||||
if (mysql_command == '\x01') {
|
if (mysql_command == '\x01') {
|
||||||
router->routeQuery(router_instance, rsession, queue);
|
router->routeQuery(router_instance, rsession, read_buffer);
|
||||||
LOGIF(LD, (skygw_log_write_flush(
|
LOGIF(LD, (skygw_log_write_flush(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
"%lu [gw_read_client_event] Routed COM_QUIT to "
|
"%lu [gw_read_client_event] Routed COM_QUIT to "
|
||||||
@ -704,10 +735,25 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/** Route other commands to backend */
|
if (stmt_input)
|
||||||
rc = router->routeQuery(router_instance,
|
{
|
||||||
|
/**
|
||||||
|
* 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,
|
rsession,
|
||||||
queue);
|
read_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/** succeed */
|
/** succeed */
|
||||||
if (rc == 1) {
|
if (rc == 1) {
|
||||||
rc = 0; /**< here '0' means success */
|
rc = 0; /**< here '0' means success */
|
||||||
@ -1193,7 +1239,6 @@ static int gw_error_client_event(DCB *dcb) {
|
|||||||
router = session->service->router;
|
router = session->service->router;
|
||||||
router_instance = session->service->router_instance;
|
router_instance = session->service->router_instance;
|
||||||
rsession = session->router_session;
|
rsession = session->router_session;
|
||||||
|
|
||||||
router->closeSession(router_instance, rsession);
|
router->closeSession(router_instance, rsession);
|
||||||
}
|
}
|
||||||
dcb_close(dcb);
|
dcb_close(dcb);
|
||||||
@ -1251,7 +1296,8 @@ gw_client_hangup_event(DCB *dcb)
|
|||||||
void* router_instance;
|
void* router_instance;
|
||||||
void* rsession;
|
void* rsession;
|
||||||
int rc = 1;
|
int rc = 1;
|
||||||
#if defined(SS_DEBUG)
|
|
||||||
|
#if defined(SS_DEBUG)
|
||||||
MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol;
|
MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol;
|
||||||
if (dcb->state == DCB_STATE_POLLING ||
|
if (dcb->state == DCB_STATE_POLLING ||
|
||||||
dcb->state == DCB_STATE_NOPOLLING ||
|
dcb->state == DCB_STATE_NOPOLLING ||
|
||||||
@ -1260,8 +1306,6 @@ gw_client_hangup_event(DCB *dcb)
|
|||||||
CHK_PROTOCOL(protocol);
|
CHK_PROTOCOL(protocol);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
CHK_DCB(dcb);
|
CHK_DCB(dcb);
|
||||||
|
|
||||||
if (dcb->state != DCB_STATE_POLLING) {
|
if (dcb->state != DCB_STATE_POLLING) {
|
||||||
@ -1278,7 +1322,6 @@ gw_client_hangup_event(DCB *dcb)
|
|||||||
router = session->service->router;
|
router = session->service->router;
|
||||||
router_instance = session->service->router_instance;
|
router_instance = session->service->router_instance;
|
||||||
rsession = session->router_session;
|
rsession = session->router_session;
|
||||||
|
|
||||||
router->closeSession(router_instance, rsession);
|
router->closeSession(router_instance, rsession);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1286,3 +1329,99 @@ gw_client_hangup_event(DCB *dcb)
|
|||||||
return_rc:
|
return_rc:
|
||||||
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;
|
conn->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));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -342,7 +342,7 @@ int gw_receive_backend_auth(
|
|||||||
/*<
|
/*<
|
||||||
* Remove data from buffer.
|
* Remove data from buffer.
|
||||||
*/
|
*/
|
||||||
head = gwbuf_consume(head, gwbuf_length(head));
|
head = gwbuf_consume(head, GWBUF_LENGTH(head));
|
||||||
}
|
}
|
||||||
else if (n == 0)
|
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;
|
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 void freeSession(ROUTER *instance, void *router_session);
|
||||||
static int execute(ROUTER *instance, void *router_session, GWBUF *queue);
|
static int execute(ROUTER *instance, void *router_session, GWBUF *queue);
|
||||||
static void diagnostics(ROUTER *instance, DCB *dcb);
|
static void diagnostics(ROUTER *instance, DCB *dcb);
|
||||||
|
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||||
|
|
||||||
/** The module object definition */
|
/** The module object definition */
|
||||||
static ROUTER_OBJECT MyObject = {
|
static ROUTER_OBJECT MyObject = {
|
||||||
@ -64,7 +65,8 @@ static ROUTER_OBJECT MyObject = {
|
|||||||
execute,
|
execute,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL,
|
||||||
|
getCapabilities
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int execute_cmd(CLI_SESSION *cli);
|
extern int execute_cmd(CLI_SESSION *cli);
|
||||||
@ -273,3 +275,10 @@ diagnostics(ROUTER *instance, DCB *dcb)
|
|||||||
{
|
{
|
||||||
return; /* Nothing to do currently */
|
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,
|
char *message,
|
||||||
DCB *backend_dcb,
|
DCB *backend_dcb,
|
||||||
int action);
|
int action);
|
||||||
|
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||||
|
|
||||||
|
|
||||||
/** The module object definition */
|
/** The module object definition */
|
||||||
static ROUTER_OBJECT MyObject = {
|
static ROUTER_OBJECT MyObject = {
|
||||||
@ -118,13 +120,14 @@ static ROUTER_OBJECT MyObject = {
|
|||||||
routeQuery,
|
routeQuery,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
clientReply,
|
clientReply,
|
||||||
errorReply
|
errorReply,
|
||||||
|
getCapabilities
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool rses_begin_router_action(
|
static bool rses_begin_locked_router_action(
|
||||||
ROUTER_CLIENT_SES* rses);
|
ROUTER_CLIENT_SES* rses);
|
||||||
|
|
||||||
static void rses_exit_router_action(
|
static void rses_end_locked_router_action(
|
||||||
ROUTER_CLIENT_SES* rses);
|
ROUTER_CLIENT_SES* rses);
|
||||||
|
|
||||||
static SPINLOCK instlock;
|
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.
|
* We now have the server with the least connections.
|
||||||
* Bump the connection count for this server
|
* Bump the connection count for this server
|
||||||
@ -517,7 +522,7 @@ DCB* backend_dcb;
|
|||||||
/**
|
/**
|
||||||
* Lock router client session for secure read and update.
|
* 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 */
|
/* decrease server current connection counter */
|
||||||
atomic_add(&router_cli_ses->backend->server->stats.n_current, -1);
|
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->backend_dcb = NULL;
|
||||||
router_cli_ses->rses_closed = true;
|
router_cli_ses->rses_closed = true;
|
||||||
/** Unlock */
|
/** Unlock */
|
||||||
rses_exit_router_action(router_cli_ses);
|
rses_end_locked_router_action(router_cli_ses);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the backend server connection
|
* 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
|
* 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)
|
if (!rses_is_closed)
|
||||||
{
|
{
|
||||||
backend_dcb = router_cli_ses->backend_dcb;
|
backend_dcb = router_cli_ses->backend_dcb;
|
||||||
/** unlock */
|
/** unlock */
|
||||||
rses_exit_router_action(router_cli_ses);
|
rses_end_locked_router_action(router_cli_ses);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rses_is_closed || backend_dcb == NULL)
|
if (rses_is_closed || backend_dcb == NULL)
|
||||||
@ -690,7 +695,7 @@ static void
|
|||||||
errorReply(
|
errorReply(
|
||||||
ROUTER *instance,
|
ROUTER *instance,
|
||||||
void *router_session,
|
void *router_session,
|
||||||
char *message,
|
char *message,
|
||||||
DCB *backend_dcb,
|
DCB *backend_dcb,
|
||||||
int action)
|
int action)
|
||||||
{
|
{
|
||||||
@ -717,7 +722,7 @@ errorReply(
|
|||||||
* @details (write detailed description here)
|
* @details (write detailed description here)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static bool rses_begin_router_action(
|
static bool rses_begin_locked_router_action(
|
||||||
ROUTER_CLIENT_SES* rses)
|
ROUTER_CLIENT_SES* rses)
|
||||||
{
|
{
|
||||||
bool succp = false;
|
bool succp = false;
|
||||||
@ -752,9 +757,17 @@ return_succp:
|
|||||||
* @details (write detailed description here)
|
* @details (write detailed description here)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void rses_exit_router_action(
|
static void rses_end_locked_router_action(
|
||||||
ROUTER_CLIENT_SES* rses)
|
ROUTER_CLIENT_SES* rses)
|
||||||
{
|
{
|
||||||
CHK_CLIENT_RSES(rses);
|
CHK_CLIENT_RSES(rses);
|
||||||
spinlock_release(&rses->rses_lock);
|
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 void freeSession(ROUTER *instance, void *session);
|
||||||
static int routeQuery(ROUTER *instance, void *session, GWBUF *queue);
|
static int routeQuery(ROUTER *instance, void *session, GWBUF *queue);
|
||||||
static void diagnostic(ROUTER *instance, DCB *dcb);
|
static void diagnostic(ROUTER *instance, DCB *dcb);
|
||||||
|
static uint8_t getCapabilities (ROUTER* inst, void* router_session);
|
||||||
|
|
||||||
|
|
||||||
static ROUTER_OBJECT MyObject = {
|
static ROUTER_OBJECT MyObject = {
|
||||||
@ -36,7 +37,8 @@ static ROUTER_OBJECT MyObject = {
|
|||||||
routeQuery,
|
routeQuery,
|
||||||
diagnostic,
|
diagnostic,
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL,
|
||||||
|
getCapabilities
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,3 +139,10 @@ static void
|
|||||||
diagnostic(ROUTER *instance, DCB *dcb)
|
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_DCB,
|
||||||
CHK_NUM_PROTOCOL,
|
CHK_NUM_PROTOCOL,
|
||||||
CHK_NUM_SESSION,
|
CHK_NUM_SESSION,
|
||||||
CHK_NUM_ROUTER_SES
|
CHK_NUM_ROUTER_SES,
|
||||||
|
CHK_NUM_MY_SESCMD,
|
||||||
|
CHK_NUM_ROUTER_PROPERTY
|
||||||
} skygw_chk_t;
|
} skygw_chk_t;
|
||||||
|
|
||||||
# define STRBOOL(b) ((b) ? "true" : "false")
|
# define STRBOOL(b) ((b) ? "true" : "false")
|
||||||
@ -214,7 +216,11 @@ typedef enum skygw_chk_t {
|
|||||||
((r) == DCB_ROLE_REQUEST_HANDLER ? "DCB_ROLE_REQUEST_HANDLER" : \
|
((r) == DCB_ROLE_REQUEST_HANDLER ? "DCB_ROLE_REQUEST_HANDLER" : \
|
||||||
"UNKNOWN DCB ROLE"))
|
"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) { \
|
#define CHK_MLIST(l) { \
|
||||||
ss_info_dassert((l->mlist_chk_top == CHK_NUM_MLIST && \
|
ss_info_dassert((l->mlist_chk_top == CHK_NUM_MLIST && \
|
||||||
l->mlist_chk_tail == 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"); \
|
"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)
|
#if defined(SS_DEBUG)
|
||||||
bool conn_open[10240];
|
bool conn_open[10240];
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user