Files
MaxScale/utils/skygw_debug.h
vraatikka 74aa3638f9 dcb.c
dcb_final_free: Router session is not closed anymore when dcb is closed. Router session is shared among all dcbs and is closed and freed with session.
	dcb_connect: dcb's state must be switched fro DCB_STATE_ALLOC to DCB_STATE_DISCONNECTED before dcb_final_free can be called for it.
	dcb_close: poll_remove_dcb encapsulates dcb's state transition in the same way as poll_add_dcb. Removed state modification from dcb_close. Read return value of poll_remove_dcb and log accordingly.
	dcb_set state: remove dassert if dcb_set_state_nomutex returned false. False can be returned indicating that intented change didn't occur but the end state, for example, may be acceptable. Failures in state transitions are asserted in dcb_Set_state_nomutex.

poll.c
	poll_add_dcb: dcb state is now set here to either DCB_STATE_LISTENING or to DCB_STATE_POLLING according to dcb's role. Failures in state setting and in epoll_ctl are detected, logged and handled.
	poll_remove_dcb: Failures in state setting and epoll_ctl are detected, logged, and handled.

mysql_client_server_protocol.h 
	Removed macros MYSQL_FAILED_AUTHENTICATION & MYSQL_SUCCESFUL_AUTHENTICATION as they were not necessary and used with constant values 0 and 1 depending on the case.
	Renamed variable 'conn' to 'protocol' in cases where it meant protocol.

mysql_backend.c
	gw_read_backend_event: In case when there was nothing to read or read failed, backend dcb is closed because situation is assumed to be such that backend server closed its side of the socket. Removed macros MYSQL_FAILED/SUCCESFUL_AUTHENTICATION
	gw_create_backend_connection: Assigned protocol with fd which is connected to backend.
	backend_write_delayqueue: In case where dcb_write fails to write anything, close backend dcb to avoid it getting hanging.

mysql_client.c
	gw_read_client_event: Read return value of routeQuery and if it isn't == 1, call mysql_send_custom_error with client dcb and set client's protocol state to MYSQL_IDLE instead of MYSQL_ROUTING.
	gw_MySQLAccept: Static reply counter was erroneously used as a criteria for jumping to return point where return value was constantly 'success' (=0). Replaced static reply counter with private. Fixed return value in different cases.

mysql_common.c
	gw_receive_backend_auth: Changed to return boolean values indicating of success or failue. Used integers which were assigned to macroed values on the caller side. Added length check before accessing buffer. 

readconnroute.c
	Cut too long lines and removed statements with side effects.

skygw_debug.h
	Added macro STRPROTOCOLSTATE(s) to produce string representation of a given protocol state.
2013-09-20 14:32:28 +03:00

384 lines
18 KiB
C

/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <stdio.h>
#include <assert.h>
#define __USE_UNIX98 1
#include <pthread.h>
#include <unistd.h>
#include <stdbool.h>
#if !defined(SKYGW_DEBUG_H)
#define SKYGW_DEBUG_H
#ifdef __cplusplus
#define EXTERN_C_BLOCK_BEGIN extern "C" {
#define EXTERN_C_BLOCK_END }
#define EXTERN_C_FUNC extern "C"
#else
#define EXTERN_C_BLOCK_BEGIN
#define EXTERN_C_BLOCK_END
#define EXTERN_C_FUNC
#endif
#if defined(SS_DEBUG)
# define SS_PROF
#endif
#if defined(SS_DEBUG) || defined(SS_PROF)
# define ss_prof(exp) exp
#else
# define ss_prof(exp)
#endif /* SS_DEBUG || SS_PROF */
#if defined(SS_DEBUG)
# define ss_debug(exp) exp
# define ss_dfprintf fprintf
# define ss_dfflush fflush
# define ss_dfwrite fwrite
# define ss_dassert(exp) \
{ \
if (!(exp)) { \
ss_dfprintf(stderr, \
"debug assert %s:%d\n", \
(char*)__FILE__, \
__LINE__); \
ss_dfflush(stderr); \
assert(exp); \
} \
}
# define ss_info_dassert(exp, info) \
{ \
if (!(exp)) { \
ss_dfprintf(stderr, "debug assert %s:%d, %s\n", \
(char *)__FILE__, \
__LINE__, \
info); \
ss_dfflush(stderr); \
assert((exp)); \
} \
}
#else /* SS_DEBUG */
# define ss_debug(exp)
# define ss_dfprintf(a, b, ...)
# define ss_dfflush(s)
# define ss_dfwrite(a, b, c, d)
# define ss_dassert(exp)
# define ss_info_dassert(exp, info)
#endif /* SS_DEBUG */
#define CHK_NUM_BASE 101
typedef enum skygw_chk_t {
CHK_NUM_SLIST = CHK_NUM_BASE,
CHK_NUM_SLIST_NODE,
CHK_NUM_SLIST_CURSOR,
CHK_NUM_MLIST,
CHK_NUM_MLIST_NODE,
CHK_NUM_MLIST_CURSOR,
CHK_NUM_QUERY_TEST,
CHK_NUM_LOGFILE,
CHK_NUM_FILEWRITER,
CHK_NUM_THREAD,
CHK_NUM_SIMPLE_MUTEX,
CHK_NUM_MESSAGE,
CHK_NUM_RWLOCK,
CHK_NUM_FNAMES,
CHK_NUM_LOGMANAGER,
CHK_NUM_FILE,
CHK_NUM_BLOCKBUF,
CHK_NUM_HASHTABLE,
CHK_NUM_DCB,
CHK_NUM_PROTOCOL,
CHK_NUM_SESSION
} skygw_chk_t;
# define STRBOOL(b) ((b) ? "true" : "false")
# define STRQTYPE(t) ((t) == QUERY_TYPE_WRITE ? "QUERY_TYPE_WRITE" : \
((t) == QUERY_TYPE_READ ? "QUERY_TYPE_READ" : \
((t) == QUERY_TYPE_SESSION_WRITE ? "QUERY_TYPE_SESSION_WRITE" : \
"QUERY_TYPE_UNKNOWN")))
#define STRLOGID(i) ((i) == LOGFILE_TRACE ? "LOGFILE_TRACE" : \
((i) == LOGFILE_MESSAGE ? "LOGFILE_MESSAGE" : \
((i) == LOGFILE_ERROR ? "LOGFILE_ERROR" : \
"Unknown logfile type")))
#define STRPACKETTYPE(p) ((p) == COM_INIT_DB ? "COM_INIT_DB" : \
((p) == COM_CREATE_DB ? "COM_CREATE_DB" : \
((p) == COM_DROP_DB ? "COM_DROP_DB" : \
((p) == COM_REFRESH ? "COM_REFRESH" : \
((p) == COM_DEBUG ? "COM_DEBUG" : \
((p) == COM_PING ? "COM_PING" : \
((p) == COM_CHANGE_USER ? "COM_CHANGE_USER" : \
((p) == COM_QUERY ? "COM_QUERY" : \
((p) == COM_SHUTDOWN ? "COM_SHUTDOWN" : \
((p) == COM_PROCESS_INFO ? "COM_PROCESS_INFO" : \
((p) == COM_CONNECT ? "COM_CONNECT" : \
((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")))))))))))))))
#define STRDCBSTATE(s) ((s) == DCB_STATE_ALLOC ? "DCB_STATE_ALLOC" : \
((s) == DCB_STATE_POLLING ? "DCB_STATE_POLLING" : \
((s) == DCB_STATE_LISTENING ? "DCB_STATE_LISTENING" : \
((s) == DCB_STATE_DISCONNECTED ? "DCB_STATE_DISCONNECTED" : \
((s) == DCB_STATE_NOPOLLING ? "DCB_STATE_NOPOLLING" : \
((s) == DCB_STATE_FREED ? "DCB_STATE_FREED" : \
((s) == DCB_STATE_ZOMBIE ? "DCB_STATE_ZOMBIE" : \
((s) == DCB_STATE_UNDEFINED ? "DCB_STATE_UNDEFINED" : "DCB_STATE_UNKNOWN"))))))))
#define STRSESSIONSTATE(s) ((s) == SESSION_STATE_ALLOC ? "SESSION_STATE_ALLOC" : \
((s) == SESSION_STATE_READY ? "SESSION_STATE_READY" : \
((s) == SESSION_STATE_LISTENER ? "SESSION_STATE_LISTENER" : \
((s) == SESSION_STATE_LISTENER_STOPPED ? "SESSION_STATE_LISTENER_STOPPED" : \
"SESSION_STATE_UNKNOWN"))))
#define STRPROTOCOLSTATE(s) ((s) == MYSQL_ALLOC ? "MYSQL_ALLOC" : \
((s) == MYSQL_PENDING_CONNECT ? "MYSQL_PENDING_CONNECT" : \
((s) == MYSQL_CONNECTED ? "MYSQL_CONNECTED" : \
((s) == MYSQL_AUTH_SENT ? "MYSQL_AUTH_SENT" : \
((s) == MYSQL_AUTH_RECV ? "MYSQL_AUTH_RECV" : \
((s) == MYSQL_AUTH_FAILED ? "MYSQL_AUTH_FAILED" : \
((s) == MYSQL_IDLE ? "MYSQL_IDLE" : \
((s) == MYSQL_ROUTING ? "MYSQL_ROUTING" : \
((s) == MYSQL_WAITING_RESULT ? "MYSQL_WAITING_RESULT" : \
((s) == MYSQL_SESSION_CHANGE ? "MYSQL_SESSION_CHANGE" : \
"UNKNOWN MYSQL STATE"))))))))))
#define CHK_MLIST(l) { \
ss_info_dassert((l->mlist_chk_top == CHK_NUM_MLIST && \
l->mlist_chk_tail == CHK_NUM_MLIST), \
"Single-linked list structure under- or overflow"); \
if (l->mlist_first == NULL) { \
ss_info_dassert(l->mlist_nodecount == 0, \
"List head is NULL but element counter is not zero."); \
ss_info_dassert(l->mlist_last == NULL, \
"List head is NULL but tail has node"); \
} else { \
ss_info_dassert(l->mlist_nodecount > 0, \
"List head has node but element counter is not " \
"positive."); \
CHK_MLIST_NODE(l->mlist_first); \
CHK_MLIST_NODE(l->mlist_last); \
} \
if (l->mlist_nodecount == 0) { \
ss_info_dassert(l->mlist_first == NULL, \
"Element counter is zero but head has node"); \
ss_info_dassert(l->mlist_last == NULL, \
"Element counter is zero but tail has node"); \
} \
}
#define CHK_MLIST_NODE(n) { \
ss_info_dassert((n->mlnode_chk_top == CHK_NUM_MLIST_NODE && \
n->mlnode_chk_tail == CHK_NUM_MLIST_NODE), \
"Single-linked list node under- or overflow"); \
}
#define CHK_MLIST_CURSOR(c) { \
ss_info_dassert(c->mlcursor_chk_top == CHK_NUM_MLIST_CURSOR && \
c->mlcursor_chk_tail == CHK_NUM_MLIST_CURSOR, \
"List cursor under- or overflow"); \
ss_info_dassert(c->mlcursor_list != NULL, \
"List cursor doesn't have list"); \
ss_info_dassert(c->mlcursor_pos != NULL || \
(c->mlcursor_pos == NULL && \
c->mlcursor_list->mlist_first == NULL), \
"List cursor doesn't have position"); \
}
#define CHK_SLIST(l) { \
ss_info_dassert((l->slist_chk_top == CHK_NUM_SLIST && \
l->slist_chk_tail == CHK_NUM_SLIST), \
"Single-linked list structure under- or overflow"); \
if (l->slist_head == NULL) { \
ss_info_dassert(l->slist_nelems == 0, \
"List head is NULL but element counter is not zero."); \
ss_info_dassert(l->slist_tail == NULL, \
"List head is NULL but tail has node"); \
} else { \
ss_info_dassert(l->slist_nelems > 0, \
"List head has node but element counter is not " \
"positive."); \
CHK_SLIST_NODE(l->slist_head); \
CHK_SLIST_NODE(l->slist_tail); \
} \
if (l->slist_nelems == 0) { \
ss_info_dassert(l->slist_head == NULL, \
"Element counter is zero but head has node"); \
ss_info_dassert(l->slist_tail == NULL, \
"Element counter is zero but tail has node"); \
} \
}
#define CHK_SLIST_NODE(n) { \
ss_info_dassert((n->slnode_chk_top == CHK_NUM_SLIST_NODE && \
n->slnode_chk_tail == CHK_NUM_SLIST_NODE), \
"Single-linked list node under- or overflow"); \
}
#define CHK_SLIST_CURSOR(c) { \
ss_info_dassert(c->slcursor_chk_top == CHK_NUM_SLIST_CURSOR && \
c->slcursor_chk_tail == CHK_NUM_SLIST_CURSOR, \
"List cursor under- or overflow"); \
ss_info_dassert(c->slcursor_list != NULL, \
"List cursor doesn't have list"); \
ss_info_dassert(c->slcursor_pos != NULL || \
(c->slcursor_pos == NULL && \
c->slcursor_list->slist_head == NULL), \
"List cursor doesn't have position"); \
}
#define CHK_QUERY_TEST(q) { \
ss_info_dassert(q->qt_chk_top == CHK_NUM_QUERY_TEST && \
q->qt_chk_tail == CHK_NUM_QUERY_TEST, \
"Query test under- or overflow."); \
}
#define CHK_LOGFILE(lf) { \
ss_info_dassert(lf->lf_chk_top == CHK_NUM_LOGFILE && \
lf->lf_chk_tail == CHK_NUM_LOGFILE, \
"Logfile struct under- or overflow"); \
ss_info_dassert(lf->lf_logpath != NULL && \
lf->lf_name_prefix != NULL && \
lf->lf_name_suffix != NULL && \
lf->lf_full_name != NULL, \
"NULL in name variable\n"); \
ss_info_dassert(lf->lf_id >= LOGFILE_FIRST && \
lf->lf_id <= LOGFILE_LAST, \
"Invalid logfile id\n"); \
(lf->lf_chk_top != CHK_NUM_LOGFILE || \
lf->lf_chk_tail != CHK_NUM_LOGFILE ? \
false : \
(lf->lf_logpath == NULL || \
lf->lf_name_prefix == NULL || \
lf->lf_name_suffix == NULL || \
lf->lf_full_name == NULL ? false : true)); \
}
#define CHK_FILEWRITER(fwr) { \
ss_info_dassert(fwr->fwr_chk_top == CHK_NUM_FILEWRITER && \
fwr->fwr_chk_tail == CHK_NUM_FILEWRITER, \
"File writer struct under- or overflow"); \
}
#define CHK_THREAD(thr) { \
ss_info_dassert(thr->sth_chk_top == CHK_NUM_THREAD && \
thr->sth_chk_tail == CHK_NUM_THREAD, \
"Thread struct under- or overflow"); \
}
#define CHK_SIMPLE_MUTEX(sm) { \
ss_info_dassert(sm->sm_chk_top == CHK_NUM_SIMPLE_MUTEX && \
sm->sm_chk_tail == CHK_NUM_SIMPLE_MUTEX, \
"Simple mutex struct under- or overflow"); \
}
#define CHK_MESSAGE(mes) { \
ss_info_dassert(mes->mes_chk_top == CHK_NUM_MESSAGE && \
mes->mes_chk_tail == CHK_NUM_MESSAGE, \
"Message struct under- or overflow"); \
}
#define CHK_MLIST_ISLOCKED(l) { \
ss_info_dassert((l.mlist_uselock && l.mlist_islocked) || \
!(l.mlist_uselock || l.mlist_islocked), \
("mlist is not locked although it should.")); \
CHK_MUTEXED_FOR_THR(l.mlist_uselock,l.mlist_rwlock); \
}
#define CHK_MUTEXED_FOR_THR(b,l) { \
ss_info_dassert(!b || \
(b && (l->srw_rwlock_thr == pthread_self())), \
"rwlock is not acquired although it should be."); \
}
#define CHK_FNAMES_CONF(fn) { \
ss_info_dassert(fn->fn_chk_top == CHK_NUM_FNAMES && \
fn->fn_chk_tail == CHK_NUM_FNAMES, \
"File names confs struct under- or overflow"); \
}
#define CHK_LOGMANAGER(lm) { \
ss_info_dassert(lm->lm_chk_top == CHK_NUM_LOGMANAGER && \
lm->lm_chk_tail == CHK_NUM_LOGMANAGER, \
"Log manager struct under- or overflow"); \
}
#define CHK_FILE(f) { \
ss_info_dassert(f->sf_chk_top == CHK_NUM_FILE && \
f->sf_chk_tail == CHK_NUM_FILE, \
"File struct under- or overflow"); \
}
#define CHK_BLOCKBUF(bb) { \
ss_info_dassert(bb->bb_chk_top == CHK_NUM_BLOCKBUF, \
"Block buf under- or overflow"); \
}
#define CHK_HASHTABLE(t) { \
ss_info_dassert(t->ht_chk_top == CHK_NUM_HASHTABLE && \
t->ht_chk_tail == CHK_NUM_HASHTABLE, \
"Hashtable under- or overflow"); \
}
#define CHK_DCB(d) { \
ss_info_dassert(d->dcb_chk_top == CHK_NUM_DCB && \
d->dcb_chk_tail == CHK_NUM_DCB, \
"Dcb under- or overflow"); \
}
#define CHK_PROTOCOL(p) { \
ss_info_dassert(p->protocol_chk_top == CHK_NUM_PROTOCOL && \
p->protocol_chk_tail == CHK_NUM_PROTOCOL, \
"Protocol under- or overflow"); \
}
#define CHK_SESSION(s) { \
ss_info_dassert(s->ses_chk_top == CHK_NUM_SESSION && \
s->ses_chk_tail == CHK_NUM_SESSION, \
"Session under- or overflow"); \
}
#define CHK_GWBUF(b) { \
ss_info_dassert(((b)->start <= (b)->end), \
"gwbuf start has passed the endpoint"); \
}
#if defined(SS_DEBUG)
bool conn_open[1024];
#endif
#endif /* SKYGW_DEBUG_H */