dcb.c, gateway.c little tuning.

poll.c
	Removed mutex from epoll_wait.
	Removed read and write mutexes from poll_waitevents.

session.c
	If session_alloc fails, instead of calling directly free(session), call session_free, which decreases refcounter and only frees session when there are no references left. 
	Added session_unlink_dcb function which removes link from session and optionally sets the dcb->session pointer to NULL.

readconnection.h, readwritesplit.h
	Added check fields to ROUTER_CLIENT_SES strct as well as lock, version number (not used yet) and closed flag.

mysql_backend.c
	gw_read_backend_event: if backend_protocol->state was set to MYSQL_AUTH_RECV, function returned, which was unnecessary. If mysql state became MYSQL_AUTH_FAILED, router client session was closed. Removed unnecessary NULL checks because rsession is not allowed to be NULL. Similarly, removed other NULL checks and replaced them with asserts checking that router client session is not NULL at any phase.

mysql_client.c
	Removed unused code blocks. Polished log commands. Replaced router client sessions NULL checks with asserts.

mysql_common.c
	mysql_send_custom_error: if called with dcb == NULL, return.

readconnroute.c
	Replaced malloc with calloc. Added functions rses_begin_router_action and rses_exit_router_action. If router client session is not closed, they take a lock and release it, respectively. Those functions are used for protecting all operations which modify the contents of router client session struct.

readwritesplit.c
	Identical changes than in readconnroute.c

skygw_debug.h
	Added check number and - macro for ROUTER_CLIENT_SES, and added COM_QUIT to STRPACKETTYPE.
This commit is contained in:
vraatikka
2013-10-30 22:07:51 +02:00
parent 5e6b0a3b1a
commit e803acb036
12 changed files with 623 additions and 359 deletions

View File

@ -226,11 +226,11 @@ dcb_final_free(DCB *dcb)
ss_info_dassert(dcb->state == DCB_STATE_DISCONNECTED,
"dcb not in DCB_STATE_DISCONNECTED state.");
/* First remove this DCB from the chain */
/** First remove this DCB from the chain */
spinlock_acquire(&dcbspin);
if (allDCBs == dcb)
{
/*
/**
* Deal with the special case of removing the DCB at the head of
* the chain.
*/
@ -238,7 +238,7 @@ dcb_final_free(DCB *dcb)
}
else
{
/*
/**
* We find the DCB that point to the one we are removing and then
* set the next pointer of that DCB to the next pointer of the
* DCB we are removing.
@ -255,8 +255,9 @@ dcb_final_free(DCB *dcb)
/**
* Terminate client session.
*/
{
SESSION *local_session = dcb->session;
{
SESSION *local_session = dcb->session;
CHK_SESSION(local_session);
/**
* Remove reference from session if dcb is client.
*/
@ -431,6 +432,7 @@ int rc;
{
return NULL;
}
if ((funcs = (GWPROTOCOL *)load_module(protocol,
MODULE_PROTOCOL)) == NULL)
{
@ -446,6 +448,9 @@ int rc;
}
memcpy(&(dcb->func), funcs, sizeof(GWPROTOCOL));
/**
* Link dcb to session. Unlink is called in dcb_final_free
*/
if (!session_link_dcb(session, dcb))
{
skygw_log_write(
@ -459,10 +464,11 @@ int rc;
fd = dcb->func.connect(dcb, server, session);
if (fd == -1) {
skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Failed to connect to server %s:%d, "
skygw_log_write(
LOGFILE_TRACE,
"%lu [dcb_connect] Failed to connect to server %s:%d, "
"from backend dcb %p, client dcp %p fd %d.",
pthread_self(),
server->name,
server->port,
dcb,
@ -489,12 +495,6 @@ int rc;
*/
dcb->fd = fd;
/*
* The dcb will be addded into poll set by dcb->func.connect
*/
atomic_add(&server->stats.n_connections, 1);
atomic_add(&server->stats.n_current, 1);
/**
* backend_dcb is connected to backend server, and once backend_dcb
* is added to poll set, authentication takes place as part of
@ -512,6 +512,11 @@ int rc;
dcb_final_free(dcb);
return NULL;
}
/*
* The dcb will be addded into poll set by dcb->func.connect
*/
atomic_add(&server->stats.n_connections, 1);
atomic_add(&server->stats.n_current, 1);
return dcb;
}

View File

@ -429,13 +429,13 @@ main(int argc, char **argv)
if (access(home, R_OK) != 0)
{
fprintf(stderr,
"The configured value of MAXSCALE_HOME '%s' does not "
"exist.\n",
"The configured value of MAXSCALE_HOME '%s' "
"does not exist.\n",
home);
skygw_log_write_flush(
LOGFILE_ERROR,
"Fatal : The configured value of MAXSCALE_HOME '%s' does "
"not exist.",
"Fatal : The configured value of MAXSCALE_HOME "
"'%s' does not exist.",
home);
exit(1);
}

View File

@ -255,7 +255,7 @@ poll_waitevents(void *arg)
{
#if BLOCKINGPOLL
nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
#else
#else /* BLOCKINGPOLL */
if (!no_op) {
skygw_log_write(LOGFILE_DEBUG,
"%lu [poll_waitevents] MaxScale thread "
@ -264,7 +264,9 @@ poll_waitevents(void *arg)
thread_id);
no_op = TRUE;
}
#if 0
simple_mutex_lock(&epoll_wait_mutex, TRUE);
#endif
if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 0)) == -1)
{
@ -282,7 +284,9 @@ poll_waitevents(void *arg)
else if (nfds == 0)
{
if (process_zombies_only) {
#if 0
simple_mutex_unlock(&epoll_wait_mutex);
#endif
goto process_zombies;
} else {
nfds = epoll_wait(epoll_fd,
@ -301,8 +305,10 @@ poll_waitevents(void *arg)
}
}
}
#if 0
simple_mutex_unlock(&epoll_wait_mutex);
#endif
#endif /* BLOCKINGPOLL */
if (nfds > 0)
{
skygw_log_write(
@ -400,7 +406,7 @@ poll_waitevents(void *arg)
eno = gw_getsockerrno(dcb->fd);
if (eno == 0) {
#if 1
#if 0
simple_mutex_lock(
&dcb->dcb_write_lock,
true);
@ -411,7 +417,7 @@ poll_waitevents(void *arg)
#endif
atomic_add(&pollStats.n_write, 1);
dcb->func.write_ready(dcb);
#if 1
#if 0
dcb->dcb_write_active = FALSE;
simple_mutex_unlock(
&dcb->dcb_write_lock);
@ -431,7 +437,7 @@ poll_waitevents(void *arg)
}
if (ev & EPOLLIN)
{
#if 1
#if 0
simple_mutex_lock(&dcb->dcb_read_lock,
true);
ss_info_dassert(!dcb->dcb_read_active,
@ -462,7 +468,7 @@ poll_waitevents(void *arg)
atomic_add(&pollStats.n_read, 1);
dcb->func.read(dcb);
}
#if 1
#if 0
dcb->dcb_read_active = FALSE;
simple_mutex_unlock(
&dcb->dcb_read_lock);

View File

@ -128,13 +128,18 @@ session_alloc(SERVICE *service, DCB *client_dcb)
session);
if (session->router_session == NULL) {
/**
* Decrease refcount, set dcb's session pointer NULL
* and set session pointer to NULL.
*/
session_free(session);
client_dcb->session = NULL;
session = NULL;
skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Failed to create router "
"client session. Freeing allocated resources.");
free(session);
session = NULL;
goto return_session;
}
}
@ -175,6 +180,36 @@ session_link_dcb(SESSION *session, DCB *dcb)
return true;
}
int session_unlink_dcb(
SESSION* session,
DCB* dcb)
{
int nlink;
CHK_SESSION(session);
spinlock_acquire(&session->ses_lock);
ss_dassert(session->refcount > 0);
/**
* Remove dcb from session's router_client_session.
*/
nlink = atomic_add(&session->refcount, -1);
nlink -= 1;
if (nlink == 0)
{
session->state = SESSION_STATE_FREE;
}
if (dcb != NULL)
{
dcb->session = NULL;
}
spinlock_release(&session->ses_lock);
return nlink;
}
/**
* Deallocate the specified session
*
@ -185,22 +220,20 @@ bool session_free(
{
bool succp = false;
SESSION *ptr;
int nlink;
CHK_SESSION(session);
spinlock_acquire(&session->ses_lock);
if (atomic_add(&session->refcount, -1) > 1)
{
/*
* There are still other references to the session
* so we simply return after decrementing the session
* count.
*/
spinlock_release(&session->ses_lock);
goto return_succp;
}
session->state = SESSION_STATE_FREE;
spinlock_release(&session->ses_lock);
/**
* Remove one reference. If there are no references left,
* free session.
*/
nlink = session_unlink_dcb(session, NULL);
if (nlink != 0) {
ss_dassert(nlink > 0);
goto return_succp;
}
/* First of all remove from the linked list */
spinlock_acquire(&session_spin);

View File

@ -45,10 +45,19 @@ typedef struct backend {
* The client session structure used within this router.
*/
typedef struct router_client_session {
#if defined(SS_DEBUG)
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 *backend; /**< Backend used by the client session */
DCB *backend_dcb; /**< DCB Connection to the backend */
struct router_client_session
*next;
#if defined(SS_DEBUG)
skygw_chk_t rses_chk_tail;
#endif
} ROUTER_CLIENT_SES;
/**

View File

@ -45,11 +45,20 @@ typedef struct backend {
* The client session structure used within this router.
*/
typedef struct router_client_session {
#if defined(SS_DEBUG)
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 */
struct router_client_session* next;
#if defined(SS_DEBUG)
skygw_chk_t rses_chk_tail;
#endif
} ROUTER_CLIENT_SES;
/**

View File

@ -169,12 +169,11 @@ static int gw_read_backend_event(DCB *dcb) {
* 3. and return
*/
if (backend_protocol->state == MYSQL_CONNECTED) {
// read mysql handshake
if (gw_read_backend_handshake(backend_protocol) != 0) {
backend_protocol->state = MYSQL_AUTH_FAILED;
rc = 1;
} else {
// handshake decoded, send the auth credentials
/* handshake decoded, send the auth credentials */
if (gw_send_authentication_to_backend(
current_session->db,
current_session->user,
@ -182,11 +181,8 @@ static int gw_read_backend_event(DCB *dcb) {
backend_protocol) != 0)
{
backend_protocol->state = MYSQL_AUTH_FAILED;
rc = 1;
} else {
backend_protocol->state = MYSQL_AUTH_RECV;
rc = 0;
goto return_rc;
}
}
}
@ -202,7 +198,7 @@ static int gw_read_backend_event(DCB *dcb) {
ROUTER_OBJECT *router = NULL;
ROUTER *router_instance = NULL;
void *rsession = NULL;
SESSION *session = dcb->session;
SESSION *session = dcb->session;
int receive_rc = 0;
CHK_SESSION(session);
@ -257,6 +253,7 @@ static int gw_read_backend_event(DCB *dcb) {
}
if (backend_protocol->state == MYSQL_AUTH_FAILED) {
/** vraa : errorHandle */
/* check the delayq before the reply */
spinlock_acquire(&dcb->authlock);
if (dcb->delayq != NULL) {
@ -267,35 +264,27 @@ static int gw_read_backend_event(DCB *dcb) {
0,
"Connection to backend lost.");
// consume all the delay queue
dcb->delayq = gwbuf_consume(dcb->delayq, gwbuf_length(dcb->delayq));
dcb->delayq = gwbuf_consume(dcb->delayq,
gwbuf_length(
dcb->delayq));
}
spinlock_release(&dcb->authlock);
/**
* Protect call of closeSession.
*/
spinlock_acquire(&session->ses_lock);
rsession = session->router_session;
session->router_session = NULL;
spinlock_release(&session->ses_lock);
if (rsession != NULL) {
skygw_log_write_flush(
LOGFILE_DEBUG,
"%lu [gw_read_backend_event] "
ss_dassert(rsession != NULL);
/**
* vraa : errorHandle
* rsession should never be NULL here.
**/
ss_dassert(rsession != NULL);
skygw_log_write_flush(
LOGFILE_DEBUG,
"%lu [gw_read_backend_event] "
"Call closeSession for backend's "
"router client session.",
pthread_self());
/* close router_session */
router->closeSession(router_instance, rsession);
} else {
skygw_log_write(
LOGFILE_DEBUG,
"%lu [gw_read_backend_event] "
"closeSession already called "
"for backend session.",
pthread_self());
}
"router client session.",
pthread_self());
/* close router_session */
router->closeSession(router_instance, rsession);
rc = 1;
goto return_rc;
} else {
@ -336,6 +325,7 @@ static int gw_read_backend_event(DCB *dcb) {
rc = dcb_read(dcb, &writebuf);
if (rc < 0) {
/** vraa : errorHandle */
/**
* Backend generated EPOLLIN event and if backend has
* failed, connection must be closed to avoid backend
@ -396,7 +386,7 @@ return_rc:
* @return 1 in success, 0 in case of failure,
*/
static int gw_write_backend_event(DCB *dcb) {
int rc;
int rc = 0;
MySQLProtocol *backend_protocol = dcb->protocol;
/**
@ -404,6 +394,7 @@ static int gw_write_backend_event(DCB *dcb) {
*/
if (dcb->state != DCB_STATE_POLLING) {
if (dcb->writeq != NULL) {
/** vraa : errorHandle */
mysql_send_custom_error(
dcb->session->client,
1,
@ -478,6 +469,7 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
*/
spinlock_acquire(&dcb->authlock);
if (dcb->state != DCB_STATE_POLLING) {
/** vraa : errorHandle */
/** Free buffer memory */
gwbuf_consume(queue, GWBUF_LENGTH(queue));
@ -542,6 +534,7 @@ static int gw_error_backend_event(DCB *dcb) {
router_instance = session->service->router_instance;
if (dcb->state != DCB_STATE_POLLING) {
/** vraa : errorHandle */
/**
* if client is not available it needs to be handled in send
* function. Session != NULL, that is known.
@ -554,6 +547,7 @@ static int gw_error_backend_event(DCB *dcb) {
rc = 0;
} else {
/** vraa : errorHandle */
mysql_send_custom_error(
dcb->session->client,
1,
@ -563,25 +557,24 @@ static int gw_error_backend_event(DCB *dcb) {
}
skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [gw_error_backend_event] Some error occurred in backend. rc = %d",
pthread_self(), rc);
"%lu [gw_error_backend_event] Some error occurred in backend. "
"rc = %d",
pthread_self(),
rc);
rsession = session->router_session;
ss_dassert(rsession != NULL);
/**
* vraa : errorHandle
* rsession should never be NULL here.
*/
skygw_log_write_flush(
LOGFILE_TRACE,
"%lu [gw_read_backend_event] "
"Call closeSession for backend "
"session.",
pthread_self());
/* close the active session */
spinlock_acquire(&session->ses_lock);
rsession = session->router_session;
session->router_session = NULL;
spinlock_release(&session->ses_lock);
if (rsession != NULL) {
skygw_log_write_flush(
LOGFILE_TRACE,
"%lu [gw_read_backend_event] "
"Call closeSession for backend "
"session.",
pthread_self());
router->closeSession(router_instance, rsession);
}
router->closeSession(router_instance, rsession);
return rc;
}
@ -613,11 +606,15 @@ static int gw_create_backend_connection(
ss_dassert(protocol != NULL);
if (protocol == NULL) {
skygw_log_write_flush(
LOGFILE_ERROR,
skygw_log_write(
LOGFILE_TRACE,
"%lu [gw_create_backend_connection] Failed to create "
"protocol object for backend connection.",
pthread_self());
skygw_log_write_flush(
LOGFILE_ERROR,
"Error: Failed to create "
"protocol object for backend connection.");
goto return_fd;
}
@ -663,7 +660,7 @@ static int gw_create_backend_connection(
ss_dassert(fd == -1);
ss_dassert(protocol->state == MYSQL_ALLOC);
skygw_log_write(
LOGFILE_ERROR,
LOGFILE_TRACE,
"%lu [gw_create_backend_connection] Connection "
"failed to %s:%i, protocol fd %d client fd %d.",
pthread_self(),
@ -688,6 +685,7 @@ return_fd:
static int
gw_backend_hangup(DCB *dcb)
{
/** vraa : errorHandle */
return 1;
}
@ -700,6 +698,7 @@ gw_backend_hangup(DCB *dcb)
static int
gw_backend_close(DCB *dcb)
{
/** vraa : errorHandle */
dcb_close(dcb);
return 1;
}
@ -756,6 +755,7 @@ static int backend_write_delayqueue(DCB *dcb)
rc = dcb_write(dcb, localq);
if (rc == 0) {
/** vraa : errorHandle */
skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [backend_write_delayqueue] Some error occurred in "
@ -825,6 +825,7 @@ static int gw_change_user(DCB *backend, SERVER *server, SESSION *in_session, GWB
free(auth_token);
if (auth_ret != 0) {
/** vraa : errorHandle */
fprintf(stderr, "<<< CLIENT AUTH FAILED for user [%s], user session will not change!\n", username);
// send the error packet

View File

@ -433,75 +433,7 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
int
gw_MySQLWrite_client(DCB *dcb, GWBUF *queue)
{
#if 1
return dcb_write(dcb, queue);
#else
int w, saved_errno = 0;
spinlock_acquire(&dcb->writeqlock);
if (dcb->writeq)
{
/*
* We have some queued data, so add our data to
* the write queue and return.
* The assumption is that there will be an EPOLLOUT
* event to drain what is already queued. We are protected
* by the spinlock, which will also be acquired by the
* the routine that drains the queue data, so we should
* not have a race condition on the event.
*/
dcb->writeq = gwbuf_append(dcb->writeq, queue);
dcb->stats.n_buffered++;
}
else
{
int len;
/*
* Loop over the buffer chain that has been passed to us
* from the reading side.
* Send as much of the data in that chain as possible and
* add any balance to the write queue.
*/
while (queue != NULL)
{
len = GWBUF_LENGTH(queue);
GW_NOINTR_CALL(
w = gw_write(dcb->fd,GWBUF_DATA(queue), len);
dcb->stats.n_writes++);
saved_errno = errno;
if (w < 0)
{
break;
}
/*
* Pull the number of bytes we have written from
* queue with have.
*/
queue = gwbuf_consume(queue, w);
if (w < len)
{
/* We didn't write all the data */
}
}
/* Buffer the balance of any data */
dcb->writeq = queue;
if (queue)
{
dcb->stats.n_buffered++;
}
}
spinlock_release(&dcb->writeqlock);
if (queue && (saved_errno != EAGAIN || saved_errno != EWOULDBLOCK))
{
/* We had a real write failure that we must deal with */
return 1;
}
return 0;
#endif
}
/**
@ -525,9 +457,10 @@ int gw_read_client_event(DCB* dcb) {
/**
* Check how many bytes are readable in dcb->fd.
*/
if (ioctl(dcb->fd, FIONREAD, &b) != 0) {
if (ioctl(dcb->fd, FIONREAD, &b) != 0) {
int eno = errno;
errno = 0;
skygw_log_write(
LOGFILE_ERROR,
"%lu [gw_read_client_event] ioctl FIONREAD for fd "
@ -539,7 +472,7 @@ int gw_read_client_event(DCB* dcb) {
dcb->state);
rc = 1;
goto return_rc;
}
}
/**
* Note that earlier b==0 was translated to closed client socket.
@ -547,48 +480,11 @@ int gw_read_client_event(DCB* dcb) {
* was closed, next write will tell, thus, with b==0 routine can
* simply return.
*/
#if 0
if (b == 0) {
skygw_log_write(
LOGFILE_TRACE,
"%lu [gw_read_client_event] Dcb %p fd %d was closed. "
"Closing dcb.",
pthread_self(),
dcb,
dcb->fd);
if (dcb->state == DCB_STATE_POLLING) {
/* Send a custom error as MySQL command reply */
mysql_send_custom_error(
dcb,
1,
0,
"ioctl returned b==0");
dcb->func.close(dcb);
}
rc = 0;
// get the backend session, if available, and close the session
session = dcb->session;
if (session != NULL) {
CHK_SESSION(session);
router = session->service->router;
router_instance = session->service->router_instance;
rsession = session->router_session;
if (rsession)
router->closeSession(router_instance, rsession);
}
goto return_rc;
}
#else
if (b == 0) {
rc = 0;
goto return_rc;
}
#endif
switch (protocol->state) {
case MYSQL_AUTH_SENT:
/*
@ -1028,12 +924,23 @@ int gw_MySQLAccept(DCB *listener)
* Exceeded system's (ENFILE) or processes
* (EMFILE) max. number of files limit.
*/
skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [gw_MySQLAccept] Error %d, %s.",
skygw_log_write(
LOGFILE_DEBUG,
"%lu [gw_MySQLAccept] Error %d, %s. ",
pthread_self(),
eno,
strerror(eno));
if (i == 0)
{
skygw_log_write_flush(
LOGFILE_ERROR,
"Error %d, %s. "
"Failed to accept new client "
"connection.",
eno,
strerror(eno));
}
i++;
usleep(100*i*i);
@ -1048,12 +955,18 @@ int gw_MySQLAccept(DCB *listener)
/**
* Other error.
*/
skygw_log_write_flush(
LOGFILE_ERROR,
skygw_log_write(
LOGFILE_DEBUG,
"%lu [gw_MySQLAccept] Error %d, %s.",
pthread_self(),
eno,
strerror(eno));
skygw_log_write_flush(
LOGFILE_ERROR,
"Error %d, %s."
"Failed to accept new client connection.",
eno,
strerror(eno));
rc = 1;
goto return_rc;
} /* if (eno == ..) */
@ -1173,20 +1086,21 @@ static int gw_error_client_event(DCB *dcb) {
CHK_PROTOCOL(protocol);
}
#endif
#if 1
session = dcb->session;
/**
* session may be NULL if session_alloc failed.
* In that case router session was not created.
*/
if (session != NULL) {
CHK_SESSION(session);
router = session->service->router;
router_instance = session->service->router_instance;
rsession = session->router_session;
if (rsession) {
router->closeSession(router_instance, rsession);
}
router->closeSession(router_instance, rsession);
}
#endif
dcb_close(dcb);
return 1;
}
@ -1207,20 +1121,20 @@ gw_client_close(DCB *dcb)
CHK_PROTOCOL(protocol);
}
#endif
#if 1
session = dcb->session;
session = dcb->session;
/**
* session may be NULL if session_alloc failed.
* In that case, router session wasn't created.
*/
if (session != NULL) {
CHK_SESSION(session);
router = session->service->router;
router_instance = session->service->router_instance;
rsession = session->router_session;
if (rsession) {
router->closeSession(router_instance, rsession);
}
router->closeSession(router_instance, rsession);
}
#endif
dcb_close(dcb);
return 1;
@ -1241,6 +1155,7 @@ gw_client_hangup_event(DCB *dcb)
ROUTER_OBJECT* router;
void* router_instance;
void* rsession;
int rc = 1;
#if defined(SS_DEBUG)
MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol;
if (dcb->state == DCB_STATE_POLLING ||
@ -1250,20 +1165,24 @@ gw_client_hangup_event(DCB *dcb)
CHK_PROTOCOL(protocol);
}
#endif
#if 1
session = dcb->session;
if (session != NULL) {
CHK_SESSION(session);
router = session->service->router;
router_instance = session->service->router_instance;
rsession = session->router_session;
if (rsession) {
router->closeSession(router_instance, rsession);
}
CHK_DCB(dcb);
if (dcb->state != DCB_STATE_POLLING) {
goto return_rc;
}
#endif
session = dcb->session;
CHK_SESSION(session);
ss_dassert(session->service != NULL);
router = session->service->router;
ss_dassert(router != NULL);
router_instance = session->service->router_instance;
rsession = session->router_session;
router->closeSession(router_instance, rsession);
dcb_close(dcb);
return 1;
return_rc:
return rc;
}

View File

@ -618,10 +618,11 @@ int gw_do_connect_to_backend(
errno = 0;
skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [gw_do_connect_to_backend] Establishing connection "
"to backend server failed. Socket creation failed due "
"Error: Establishing connection to backend server "
"%s:%d failed. Socket creation failed due "
"%d, %s.",
pthread_self(),
host,
port,
eno,
strerror(eno));
rv = -1;
@ -646,10 +647,8 @@ int gw_do_connect_to_backend(
skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [gw_do_connect_to_backend] Failed to "
"connect backend server %s:%d, "
"Error: Failed to connect backend server %s:%d, "
"due %d, %s.",
pthread_self(),
host,
port,
eno,
@ -662,9 +661,8 @@ int gw_do_connect_to_backend(
errno = 0;
skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [gw_do_connect_to_backend] Failed to "
"Error: Failed to "
"close socket %d due %d, %s.",
pthread_self(),
oldfd,
eno,
strerror(eno));
@ -751,6 +749,9 @@ mysql_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, cons
GWBUF *buf = NULL;
if (dcb == NULL) {
return 0;
}
ss_dassert(dcb != NULL);
mysql_errno = 2003;

View File

@ -117,6 +117,12 @@ static ROUTER_OBJECT MyObject = {
errorReply
};
static bool rses_begin_router_action(
ROUTER_CLIENT_SES* rses);
static void rses_exit_router_action(
ROUTER_CLIENT_SES* rses);
static SPINLOCK instlock;
static ROUTER_INSTANCE *instances;
@ -175,14 +181,12 @@ ROUTER_INSTANCE *inst;
SERVER *server;
int i, n;
if ((inst = malloc(sizeof(ROUTER_INSTANCE))) == NULL)
return NULL;
memset(&inst->stats, 0, sizeof(ROUTER_STATS));
if ((inst = calloc(1, sizeof(ROUTER_INSTANCE))) == NULL) {
return NULL;
}
inst->service = service;
spinlock_init(&inst->lock);
inst->connections = NULL;
/*
* We need an array of the backend servers in the instance structure so
@ -273,7 +277,7 @@ static void *
newSession(ROUTER *instance, SESSION *session)
{
ROUTER_INSTANCE *inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES *client_ses;
ROUTER_CLIENT_SES *client_rses;
BACKEND *candidate = NULL;
int i;
@ -286,28 +290,34 @@ int i;
inst);
client_ses = (ROUTER_CLIENT_SES *)malloc(sizeof(ROUTER_CLIENT_SES));
client_rses = (ROUTER_CLIENT_SES *)calloc(1, sizeof(ROUTER_CLIENT_SES));
if (client_ses == NULL) {
if (client_rses == NULL) {
return NULL;
}
/*
#if defined(SS_DEBUG)
client_rses->rses_chk_top = CHK_NUM_ROUTER_SES;
client_rses->rses_chk_tail = CHK_NUM_ROUTER_SES;
#endif
/**
* Find a backend server to connect to. This is the extent of the
* load balancing algorithm we need to implement for this simple
* connection router.
*/
/*
* Loop over all the servers and find any that have fewer connections than our
* candidate server.
* Loop over all the servers and find any that have fewer connections
* than the candidate server.
*
* If a server has less connections than the current candidate we mark this
* as the new candidate to connect to.
*
* If a server has the same number of connections currently as the candidate
* and has had less connections over time than the candidate it will also
* become the new candidate. This has the effect of spreading the connections
* over different servers during periods of very low load.
* become the new candidate. This has the effect of spreading the
* connections over different servers during periods of very low load.
*/
for (i = 0; inst->servers[i]; i++) {
if(inst->servers[i]) {
@ -325,7 +335,8 @@ int i;
if (inst->servers[i] &&
SERVER_IS_RUNNING(inst->servers[i]->server) &&
(inst->servers[i]->server->status & inst->bitmask) == inst->bitvalue)
(inst->servers[i]->server->status & inst->bitmask) ==
inst->bitvalue)
{
/* If no candidate set, set first running server as
our initial candidate server */
@ -361,7 +372,7 @@ int i;
"Error : Failed to create new routing session. "
"Couldn't find eligible candidate server. Freeing "
"allocated resources.");
free(client_ses);
free(client_rses);
return NULL;
}
@ -370,7 +381,7 @@ int i;
* Bump the connection count for this server
*/
atomic_add(&candidate->current_connection_count, 1);
client_ses->backend = candidate;
client_rses->backend = candidate;
skygw_log_write(
LOGFILE_TRACE,
"%lu [newSession] Selected server in port %d. "
@ -380,31 +391,30 @@ int i;
candidate->current_connection_count);
/*
* Open a backend connection, putting the DCB for this
* connection in the client_ses->backend_dcb
* connection in the client_rses->backend_dcb
*/
client_ses->backend_dcb = dcb_connect(candidate->server,
client_rses->backend_dcb = dcb_connect(candidate->server,
session,
candidate->server->protocol);
if (client_ses->backend_dcb == NULL)
if (client_rses->backend_dcb == NULL)
{
atomic_add(&candidate->current_connection_count, -1);
skygw_log_write(
LOGFILE_ERROR,
"Error : Failed to create new routing session. "
"Couldn't establish connection to candidate server "
"listening to port %d. Freeing allocated resources.",
candidate->server->port);
free(client_ses);
free(client_rses);
return NULL;
}
inst->stats.n_sessions++;
/* Add this session to the list of active sessions */
/**
* Add this session to the list of active sessions.
*/
spinlock_acquire(&inst->lock);
client_ses->next = inst->connections;
inst->connections = client_ses;
client_rses->next = inst->connections;
inst->connections = client_rses;
spinlock_release(&inst->lock);
return (void *)client_ses;
CHK_CLIENT_RSES(client_rses);
return (void *)client_rses;
}
/**
@ -478,14 +488,29 @@ static void freeSession(
static void
closeSession(ROUTER *instance, void *router_session)
{
ROUTER_INSTANCE *router_inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES *router_ses = (ROUTER_CLIENT_SES *)router_session;
bool succp = false;
ROUTER_CLIENT_SES *router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
DCB* backend_dcb;
/*
* Close the connection to the backend
*/
router_ses->backend_dcb->func.close(router_ses->backend_dcb);
CHK_CLIENT_RSES(router_cli_ses);
/**
* Lock router client session for secure read and update.
*/
if (rses_begin_router_action(router_cli_ses))
{
backend_dcb = router_cli_ses->backend_dcb;
router_cli_ses->backend_dcb = NULL;
router_cli_ses->rses_closed = true;
/** Unlock */
rses_exit_router_action(router_cli_ses);
/**
* Close the backend server connection
*/
if (backend_dcb != NULL) {
CHK_DCB(backend_dcb);
backend_dcb->func.close(backend_dcb);
}
}
}
/**
@ -502,39 +527,69 @@ static int
routeQuery(ROUTER *instance, void *router_session, GWBUF *queue)
{
ROUTER_INSTANCE *inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES *rsession = (ROUTER_CLIENT_SES *)router_session;
ROUTER_CLIENT_SES *router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
uint8_t *payload = GWBUF_DATA(queue);
int mysql_command;
int rc;
DCB* backend_dcb;
bool rses_is_closed;
inst->stats.n_queries++;
mysql_command = MYSQL_GET_COMMAND(payload);
switch(mysql_command) {
case MYSQL_COM_CHANGE_USER:
rc = rsession->backend_dcb->func.auth(
rsession->backend_dcb,
NULL,
rsession->backend_dcb->session,
queue);
break;
default:
rc = rsession->backend_dcb->func.write(
rsession->backend_dcb,
queue);
/** Dirty read for quick check if router is closed. */
if (router_cli_ses->rses_closed)
{
rses_is_closed = true;
}
else
{
/**
* Lock router client session for secure read of DCBs
*/
rses_is_closed = !(rses_begin_router_action(router_cli_ses));
}
CHK_PROTOCOL(((MySQLProtocol*)rsession->backend_dcb->protocol));
if (!rses_is_closed)
{
backend_dcb = router_cli_ses->backend_dcb;
/** unlock */
rses_exit_router_action(router_cli_ses);
}
if (rses_is_closed || backend_dcb == NULL)
{
skygw_log_write(
LOGFILE_ERROR,
"Error: Failed to route MySQL command %d to backend "
"server.",
mysql_command);
goto return_rc;
}
switch(mysql_command) {
case MYSQL_COM_CHANGE_USER:
rc = backend_dcb->func.auth(
backend_dcb,
NULL,
backend_dcb->session,
queue);
break;
default:
rc = backend_dcb->func.write(backend_dcb, queue);
break;
}
CHK_PROTOCOL(((MySQLProtocol*)backend_dcb->protocol));
skygw_log_write(
LOGFILE_DEBUG,
"%lu [readconnroute:routeQuery] Routed command %d to dcb %p "
"with return value %d.",
pthread_self(),
mysql_command,
rsession->backend_dcb,
backend_dcb,
rc);
return_rc:
return rc;
}
@ -621,3 +676,62 @@ errorReply(
ss_dassert(client != NULL);
}
/** to be inline'd */
/**
* @node Acquires lock to router client session if it is not closed.
*
* Parameters:
* @param rses - in, use
*
*
* @return true if router session was not closed. If return value is true
* it means that router is locked, and must be unlocked later. False, if
* router was closed before lock was acquired.
*
*
* @details (write detailed description here)
*
*/
static bool rses_begin_router_action(
ROUTER_CLIENT_SES* rses)
{
bool succp = false;
CHK_CLIENT_RSES(rses);
if (rses->rses_closed) {
goto return_succp;
}
spinlock_acquire(&rses->rses_lock);
if (rses->rses_closed) {
spinlock_release(&rses->rses_lock);
goto return_succp;
}
succp = true;
return_succp:
return succp;
}
/** to be inline'd */
/**
* @node Releases router client session lock.
*
* Parameters:
* @param rses - <usage>
* <description>
*
* @return void
*
*
* @details (write detailed description here)
*
*/
static void rses_exit_router_action(
ROUTER_CLIENT_SES* rses)
{
CHK_CLIENT_RSES(rses);
ss_dassert(((SPINLOCK)rses->rses_lock).lock == 1);
spinlock_release(&rses->rses_lock);
}

View File

@ -80,6 +80,11 @@ static ROUTER_OBJECT MyObject = {
clientReply,
NULL
};
static bool rses_begin_router_action(
ROUTER_CLIENT_SES* rses);
static void rses_exit_router_action(
ROUTER_CLIENT_SES* rses);
static SPINLOCK instlock;
static ROUTER_INSTANCE* instances;
@ -145,7 +150,6 @@ static ROUTER* createInstance(
}
router->service = service;
spinlock_init(&router->lock);
router->connections = NULL;
/** Calculate number of servers */
server = service->databases;
@ -268,12 +272,17 @@ static void* newSession(
bool succp;
client_rses =
(ROUTER_CLIENT_SES *)malloc(sizeof(ROUTER_CLIENT_SES));
(ROUTER_CLIENT_SES *)calloc(1, sizeof(ROUTER_CLIENT_SES));
if (client_rses == NULL)
{
return NULL;
ss_dassert(false);
return NULL;
}
#if defined(SS_DEBUG)
client_rses->rses_chk_top = CHK_NUM_ROUTER_SES;
client_rses->rses_chk_tail = CHK_NUM_ROUTER_SES;
#endif
/**
* Find a backend server to connect to. This is the extent of the
* load balancing algorithm we need to implement for this simple
@ -294,6 +303,7 @@ static void* newSession(
be_slave->backend_server->protocol);
if (client_rses->slave_dcb == NULL) {
ss_dassert(session->refcount == 1);
free(client_rses);
return NULL;
}
@ -322,6 +332,11 @@ static void* newSession(
client_rses->be_master = be_master;
router->stats.n_sessions += 1;
/**
* Version is bigger than zero once initialized.
*/
atomic_add(&client_rses->rses_versno, 2);
ss_dassert(client_rses->rses_versno == 2);
/**
* Add this session to end of the list of active sessions in router.
*/
@ -330,6 +345,8 @@ static void* newSession(
router->connections = client_rses;
spinlock_release(&router->lock);
CHK_CLIENT_RSES(client_rses);
return (void *)client_rses;
}
@ -345,13 +362,38 @@ static void closeSession(
void* router_session)
{
ROUTER_CLIENT_SES* router_cli_ses;
DCB* slave_dcb;
DCB* master_dcb;
router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
CHK_CLIENT_RSES(router_cli_ses);
/**
* Close the connection to the backend servers
* Lock router client session for secure read and update.
*/
router_cli_ses->slave_dcb->func.close(router_cli_ses->slave_dcb);
router_cli_ses->master_dcb->func.close(router_cli_ses->master_dcb);
if (rses_begin_router_action(router_cli_ses))
{
slave_dcb = router_cli_ses->slave_dcb;
router_cli_ses->slave_dcb = NULL;
master_dcb = router_cli_ses->master_dcb;
router_cli_ses->master_dcb = NULL;
router_cli_ses->rses_closed = true;
/** Unlock */
rses_exit_router_action(router_cli_ses);
/**
* Close the backend server connections
*/
if (slave_dcb != NULL) {
CHK_DCB(slave_dcb);
slave_dcb->func.close(slave_dcb);
}
if (master_dcb != NULL) {
master_dcb->func.close(master_dcb);
CHK_DCB(master_dcb);
}
}
}
static void freeSession(
@ -415,21 +457,27 @@ static void freeSession(
static int routeQuery(
ROUTER* instance,
void* router_session,
GWBUF* queue)
GWBUF* querybuf)
{
skygw_query_type_t qtype = QUERY_TYPE_UNKNOWN;
char* querystr = NULL;
char* startpos;
size_t len;
unsigned char packet_type, *packet;
unsigned char packet_type;
unsigned char* packet;
int ret = 0;
GWBUF *cq = NULL;
DCB* master_dcb = NULL;
DCB* slave_dcb = NULL;
GWBUF* bufcopy = NULL;
ROUTER_INSTANCE* inst = (ROUTER_INSTANCE *)instance;
ROUTER_CLIENT_SES* router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
bool rses_is_closed;
CHK_CLIENT_RSES(router_cli_ses);
inst->stats.n_queries++;
packet = GWBUF_DATA(queue);
packet = GWBUF_DATA(querybuf);
packet_type = packet[4];
startpos = (char *)&packet[5];
len = packet[0];
@ -470,6 +518,42 @@ static int routeQuery(
break;
} /**< switch by packet type */
/** Dirty read for quick check if router is closed. */
if (router_cli_ses->rses_closed)
{
rses_is_closed = true;
}
else
{
/**
* Lock router client session for secure read of DCBs
*/
rses_is_closed = !(rses_begin_router_action(router_cli_ses));
}
if (!rses_is_closed)
{
master_dcb = router_cli_ses->master_dcb;
slave_dcb = router_cli_ses->slave_dcb;
/** unlock */
rses_exit_router_action(router_cli_ses);
}
if (rses_is_closed || (master_dcb == NULL && slave_dcb == NULL))
{
skygw_log_write(
LOGFILE_ERROR,
"Error: Failed to route %s:%s:\"%s\" to backend server. "
"%s.",
STRPACKETTYPE(packet_type),
STRQTYPE(qtype),
querystr,
(rses_is_closed ? "Router was closed" :
"Router has no backend servers where to route to"));
goto return_ret;
}
skygw_log_write(LOGFILE_TRACE, "String\t\"%s\"", querystr);
skygw_log_write(LOGFILE_TRACE,
"Packet type\t%s",
@ -483,10 +567,9 @@ static int routeQuery(
pthread_self(),
STRQTYPE(qtype));
ret = router_cli_ses->master_dcb->func.write(
router_cli_ses->master_dcb,
queue);
atomic_add(&inst->stats.n_master, 1);
ret = master_dcb->func.write(master_dcb, querybuf);
atomic_add(&inst->stats.n_master, 1);
goto return_ret;
break;
@ -497,10 +580,9 @@ static int routeQuery(
pthread_self(),
STRQTYPE(qtype));
ret = router_cli_ses->slave_dcb->func.write(
router_cli_ses->slave_dcb,
queue);
atomic_add(&inst->stats.n_slave, 1);
ret = slave_dcb->func.write(slave_dcb, querybuf);
atomic_add(&inst->stats.n_slave, 1);
goto return_ret;
break;
@ -516,36 +598,30 @@ static int routeQuery(
* the command must be executed in them.
*/
cq = gwbuf_clone(queue);
bufcopy = gwbuf_clone(querybuf);
switch(packet_type) {
case COM_QUIT:
ret = router_cli_ses->master_dcb->func.write(
router_cli_ses->master_dcb,
queue);
router_cli_ses->slave_dcb->func.write(
router_cli_ses->slave_dcb,
cq);
ret = master_dcb->func.write(master_dcb, querybuf);
slave_dcb->func.write(slave_dcb, bufcopy);
break;
case COM_CHANGE_USER:
router_cli_ses->master_dcb->func.auth(
router_cli_ses->master_dcb,
master_dcb->func.auth(
master_dcb,
NULL,
router_cli_ses->master_dcb->session,
queue);
router_cli_ses->slave_dcb->func.auth(
router_cli_ses->slave_dcb,
master_dcb->session,
querybuf);
slave_dcb->func.auth(
slave_dcb,
NULL,
router_cli_ses->master_dcb->session,
cq);
master_dcb->session,
bufcopy);
break;
default:
ret = router_cli_ses->master_dcb->func.session(
router_cli_ses->master_dcb,
(void *)queue);
router_cli_ses->slave_dcb->func.session(
router_cli_ses->slave_dcb,
(void *)cq);
ret = master_dcb->func.session(master_dcb, (void *)querybuf);
slave_dcb->func.session(slave_dcb, (void *)bufcopy);
break;
} /**< switch by packet type */
@ -560,11 +636,12 @@ static int routeQuery(
pthread_self(),
STRQTYPE(qtype));
/** Is this really ok? */
ret = router_cli_ses->master_dcb->func.write(
router_cli_ses->master_dcb,
queue);
atomic_add(&inst->stats.n_master, 1);
/**
* Is this really ok?
* What is not known is routed to master.
*/
ret = master_dcb->func.write(master_dcb, querybuf);
atomic_add(&inst->stats.n_master, 1);
goto return_ret;
break;
} /**< switch by query type */
@ -574,6 +651,67 @@ return_ret:
return ret;
}
/** to be inline'd */
/**
* @node Acquires lock to router client session if it is not closed.
*
* Parameters:
* @param rses - in, use
*
*
* @return true if router session was not closed. If return value is true
* it means that router is locked, and must be unlocked later. False, if
* router was closed before lock was acquired.
*
*
* @details (write detailed description here)
*
*/
static bool rses_begin_router_action(
ROUTER_CLIENT_SES* rses)
{
bool succp = false;
CHK_CLIENT_RSES(rses);
if (rses->rses_closed) {
goto return_succp;
}
spinlock_acquire(&rses->rses_lock);
if (rses->rses_closed) {
spinlock_release(&rses->rses_lock);
goto return_succp;
}
succp = true;
return_succp:
return succp;
}
/** to be inline'd */
/**
* @node Releases router client session lock.
*
* Parameters:
* @param rses - <usage>
* <description>
*
* @return void
*
*
* @details (write detailed description here)
*
*/
static void rses_exit_router_action(
ROUTER_CLIENT_SES* rses)
{
CHK_CLIENT_RSES(rses);
ss_dassert(((SPINLOCK)rses->rses_lock).lock == 1);
spinlock_release(&rses->rses_lock);
}
/**
* Diagnostics routine
*
@ -631,7 +769,7 @@ int i = 0;
static void clientReply(
ROUTER* instance,
void* router_session,
GWBUF* queue,
GWBUF* writebuf,
DCB* backend_dcb)
{
DCB* master_dcb;
@ -639,22 +777,40 @@ static void clientReply(
ROUTER_CLIENT_SES* router_cli_ses;
router_cli_ses = (ROUTER_CLIENT_SES *)router_session;
ss_dassert(router_cli_ses != NULL);
master_dcb = router_cli_ses->master_dcb;
client_dcb = backend_dcb->session->client;
CHK_CLIENT_RSES(router_cli_ses);
if (backend_dcb->command == ROUTER_CHANGE_SESSION) {
/* if backend_dcb is the master we can reply to the client */
if (backend_dcb == master_dcb) {
client_dcb->func.write(client_dcb, queue);
} else {
/* just consume the gwbuf without writing to the client */
gwbuf_consume(queue, gwbuf_length(queue));
}
} else {
/* normal flow */
client_dcb->func.write(client_dcb, queue);
}
/**
* Lock router client session for secure read of router session members.
* Note that this could be done without lock by using version #
*/
if (rses_begin_router_action(router_cli_ses))
{
master_dcb = router_cli_ses->master_dcb;
/** Unlock */
rses_exit_router_action(router_cli_ses);
client_dcb = backend_dcb->session->client;
if (backend_dcb != NULL &&
backend_dcb->command == ROUTER_CHANGE_SESSION)
{
/* if backend_dcb is master we can reply to client */
if (client_dcb != NULL &&
backend_dcb == master_dcb)
{
client_dcb->func.write(client_dcb, writebuf);
} else {
/* consume the gwbuf without writing to client */
gwbuf_consume(writebuf, gwbuf_length(writebuf));
}
}
else if (client_dcb != NULL)
{
/* normal flow */
client_dcb->func.write(client_dcb, writebuf);
}
}
}
/**
@ -710,8 +866,8 @@ static bool search_backend_servers(
if (be != NULL) {
skygw_log_write(
LOGFILE_TRACE,
"%lu [newSession] Examine server %s:%d with "
"%d connections. Status is %d, "
"%lu [search_backend_servers] Examine server %s:%d "
"with %d connections. Status is %d, "
"router->bitvalue is %d",
pthread_self(),
be->backend_server->name,
@ -792,8 +948,8 @@ static bool search_backend_servers(
*p_slave = be_slave;
skygw_log_write(
LOGFILE_TRACE,
"%lu [readwritesplit:newSession] Selected Slave %s:%d "
"from %d candidates.",
"%lu [readwritesplit:search_backend_servers] Selected "
"Slave %s:%d from %d candidates.",
pthread_self(),
be_slave->backend_server->name,
be_slave->backend_server->port,
@ -803,7 +959,8 @@ static bool search_backend_servers(
*p_master = be_master;
skygw_log_write(
LOGFILE_TRACE,
"%lu [readwritesplit:newSession] Selected Master %s:%d "
"%lu [readwritesplit:search_backend_servers] Selected "
"Master %s:%d "
"from %d candidates.",
pthread_self(),
be_master->backend_server->name,

View File

@ -114,7 +114,8 @@ typedef enum skygw_chk_t {
CHK_NUM_HASHTABLE,
CHK_NUM_DCB,
CHK_NUM_PROTOCOL,
CHK_NUM_SESSION
CHK_NUM_SESSION,
CHK_NUM_ROUTER_SES
} skygw_chk_t;
# define STRBOOL(b) ((b) ? "true" : "false")
@ -143,7 +144,9 @@ typedef enum skygw_chk_t {
((p) == COM_PROCESS_KILL ? "COM_PROCESS_KILL" : \
((p) == COM_TIME ? "COM_TIME" : \
((p) == COM_DELAYED_INSERT ? "COM_DELAYED_INSERT" : \
((p) == COM_DAEMON ? "COM_DAEMON" : "UNKNOWN MYSQL PACKET TYPE")))))))))))))))
((p) == COM_DAEMON ? "COM_DAEMON" : \
((p) == COM_QUIT ? "COM_QUIT" : \
"UNKNOWN MYSQL PACKET TYPE"))))))))))))))))
#define STRDCBSTATE(s) ((s) == DCB_STATE_ALLOC ? "DCB_STATE_ALLOC" : \
((s) == DCB_STATE_POLLING ? "DCB_STATE_POLLING" : \
@ -413,6 +416,13 @@ typedef enum skygw_chk_t {
"gwbuf start has passed the endpoint"); \
}
#define CHK_CLIENT_RSES(r) { \
ss_info_dassert((r)->rses_chk_top == CHK_NUM_ROUTER_SES && \
(r)->rses_chk_tail == CHK_NUM_ROUTER_SES, \
"Router client session has invalid check fields"); \
}
#if defined(SS_DEBUG)
bool conn_open[10240];
#endif