Merge branch 'develop' into firewall

This commit is contained in:
Markus Makela 2014-11-11 14:18:44 +02:00
commit 4a8f97d2e2
28 changed files with 663 additions and 242 deletions

View File

@ -152,7 +152,7 @@ add_custom_target(buildtests
add_custom_target(testall add_custom_target(testall
COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DBUILD_TYPE=Debug -DINSTALL_DIR=${CMAKE_BINARY_DIR} -DINSTALL_SYSTEM_FILES=N ${CMAKE_SOURCE_DIR} COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DBUILD_TYPE=Debug -DINSTALL_DIR=${CMAKE_BINARY_DIR} -DINSTALL_SYSTEM_FILES=N ${CMAKE_SOURCE_DIR}
COMMAND make install COMMAND make install
COMMAND cp ${CMAKE_SOURCE_DIR}/server/test/MaxScale_test.cnf ${CMAKE_BINARY_DIR}/etc/MaxScale.cnf COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/server/test/MaxScale_test.cnf ${CMAKE_BINARY_DIR}/etc/MaxScale.cnf
COMMAND /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null" COMMAND /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null"
COMMAND /bin/sh -c "make test || echo \"Test results written to: ${CMAKE_BINARY_DIR}/Testing/Temporary/\"" COMMAND /bin/sh -c "make test || echo \"Test results written to: ${CMAKE_BINARY_DIR}/Testing/Temporary/\""
COMMAND killall maxscale COMMAND killall maxscale

View File

@ -276,6 +276,8 @@ static bool check_file_and_path(
bool* writable); bool* writable);
static bool file_is_symlink(char* filename); static bool file_is_symlink(char* filename);
static int skygw_log_disable_raw(logfile_id_t id, bool emergency); /*< no locking */
const char* get_suffix_default(void) const char* get_suffix_default(void)
{ {
@ -1185,25 +1187,36 @@ return_err:
return err; return err;
} }
int skygw_log_disable( int skygw_log_disable(
logfile_id_t id) logfile_id_t id) /*< no locking */
{
int rc;
rc = skygw_log_disable_raw(id, false);
return rc;
}
static int skygw_log_disable_raw(
logfile_id_t id,
bool emergency) /*< no locking */
{ {
bool err = 0; bool err = 0;
if (!logmanager_register(true)) { if (!logmanager_register(true))
//fprintf(stderr, "ERROR: Can't register to logmanager\n"); {
err = -1; err = -1;
goto return_err; goto return_err;
} }
CHK_LOGMANAGER(lm); CHK_LOGMANAGER(lm);
if (logfile_set_enabled(id, false)) { if (emergency || logfile_set_enabled(id, false))
lm->lm_enabled_logfiles &= ~id; {
/** lm->lm_enabled_logfiles &= ~id;
* Set global variable /**
*/ * Set global variable
lm_enabled_logfiles_bitmask = lm->lm_enabled_logfiles; */
lm_enabled_logfiles_bitmask = lm->lm_enabled_logfiles;
} }
logmanager_unregister(); logmanager_unregister();
@ -2403,6 +2416,7 @@ static bool filewriter_init(
skygw_message_t* logmes) skygw_message_t* logmes)
{ {
bool succp = false; bool succp = false;
int err;
logfile_t* lf; logfile_t* lf;
logfile_id_t id; logfile_id_t id;
int i; int i;
@ -2456,10 +2470,22 @@ static bool filewriter_init(
} else { } else {
start_msg_str = strdup("---\tLogging is disabled.\n"); start_msg_str = strdup("---\tLogging is disabled.\n");
} }
skygw_file_write(fw->fwr_file[id], err = skygw_file_write(fw->fwr_file[id],
(void *)start_msg_str, (void *)start_msg_str,
strlen(start_msg_str), strlen(start_msg_str),
true); true);
if (err != 0)
{
fprintf(stderr,
"Error : writing to file %s failed due to %d, %s. "
"Exiting MaxScale.\n",
lf->lf_full_file_name,
err,
strerror(err));
succp = false;
goto return_succp;
}
free(start_msg_str); free(start_msg_str);
} }
fw->fwr_state = RUN; fw->fwr_state = RUN;
@ -2603,7 +2629,10 @@ static void* thr_filewriter_fun(
#endif #endif
node = bb_list->mlist_first; node = bb_list->mlist_first;
while (node != NULL) { while (node != NULL)
{
int err = 0;
CHK_MLIST_NODE(node); CHK_MLIST_NODE(node);
bb = (blockbuf_t *)node->mlnode_data; bb = (blockbuf_t *)node->mlnode_data;
CHK_BLOCKBUF(bb); CHK_BLOCKBUF(bb);
@ -2630,11 +2659,25 @@ static void* thr_filewriter_fun(
true); true);
} }
skygw_file_write(file, err = skygw_file_write(
(void *)bb->bb_buf, file,
bb->bb_buf_used, (void *)bb->bb_buf,
(flush_logfile || bb->bb_buf_used,
flushall_logfiles)); (flush_logfile ||
flushall_logfiles));
if (err)
{
fprintf(stderr,
"Error : Write to %s log "
": %s failed due to %d, "
"%s. Disabling the log.",
STRLOGNAME((logfile_id_t)i),
lf->lf_full_file_name,
err,
strerror(err));
/** Force log off */
skygw_log_disable_raw((logfile_id_t)i, true);
}
/** /**
* Reset buffer's counters and mark * Reset buffer's counters and mark
* not full. * not full.

View File

@ -57,7 +57,7 @@ int main(int argc, char** argv)
{ {
fgets(readbuff,4092,infile); fgets(readbuff,4092,infile);
psize = strlen(readbuff); psize = strlen(readbuff);
if(psize < 0 || psize > 4092){ if(psize > 4092){
continue; continue;
} }
qbuff = gwbuf_alloc(psize + 7); qbuff = gwbuf_alloc(psize + 7);

View File

@ -1393,11 +1393,11 @@ SERVER *server;
user, user,
auth); auth);
if (enable_root_user) if (enable_root_user)
serviceEnableRootUser(service, atoi(enable_root_user)); serviceEnableRootUser(obj->element, atoi(enable_root_user));
if (allow_localhost_match_wildcard_host && service) if (allow_localhost_match_wildcard_host)
serviceEnableLocalhostMatchWildcardHost( serviceEnableLocalhostMatchWildcardHost(
service, obj->element,
atoi(allow_localhost_match_wildcard_host)); atoi(allow_localhost_match_wildcard_host));
} }
} }

View File

@ -121,8 +121,8 @@ DCB *rval;
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
rval->dcb_chk_top = CHK_NUM_DCB; rval->dcb_chk_top = CHK_NUM_DCB;
rval->dcb_chk_tail = CHK_NUM_DCB; rval->dcb_chk_tail = CHK_NUM_DCB;
rval->dcb_errhandle_called = false;
#endif #endif
rval->dcb_errhandle_called = false;
rval->dcb_role = role; rval->dcb_role = role;
spinlock_init(&rval->dcb_initlock); spinlock_init(&rval->dcb_initlock);
spinlock_init(&rval->writeqlock); spinlock_init(&rval->writeqlock);
@ -862,7 +862,7 @@ int below_water;
while (queue != NULL) while (queue != NULL)
{ {
int qlen; int qlen;
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER && if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER &&
dcb->session != NULL) dcb->session != NULL)
{ {
@ -878,7 +878,7 @@ int below_water;
fail_next_backend_fd = false; fail_next_backend_fd = false;
} }
} }
#endif /* SS_DEBUG */ #endif /* FAKE_CODE */
qlen = GWBUF_LENGTH(queue); qlen = GWBUF_LENGTH(queue);
GW_NOINTR_CALL( GW_NOINTR_CALL(
w = gw_write( w = gw_write(
@ -1684,7 +1684,7 @@ int gw_write(
size_t nbytes) size_t nbytes)
{ {
int w; int w;
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
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 */
@ -1698,7 +1698,7 @@ int gw_write(
} }
#else #else
w = write(fd, buf, nbytes); w = write(fd, buf, nbytes);
#endif /* SS_DEBUG && SS_TEST */ #endif /* FAKE_CODE */
#if defined(SS_DEBUG_MYSQL) #if defined(SS_DEBUG_MYSQL)
{ {

View File

@ -1025,7 +1025,7 @@ int main(int argc, char **argv)
progname = *argv; progname = *argv;
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
memset(conn_open, 0, sizeof(bool)*10240); memset(conn_open, 0, sizeof(bool)*10240);
memset(dcb_fake_write_errno, 0, sizeof(unsigned char)*10240); memset(dcb_fake_write_errno, 0, sizeof(unsigned char)*10240);
memset(dcb_fake_write_ev, 0, sizeof(__int32_t)*10240); memset(dcb_fake_write_ev, 0, sizeof(__int32_t)*10240);
@ -1033,7 +1033,7 @@ int main(int argc, char **argv)
fail_next_client_fd = false; fail_next_client_fd = false;
fail_next_accept = 0; fail_next_accept = 0;
fail_accept_errno = 0; fail_accept_errno = 0;
#endif #endif /* FAKE_CODE */
file_write_header(stderr); file_write_header(stderr);
/*< /*<
* Register functions which are called at exit except libmysqld-related, * Register functions which are called at exit except libmysqld-related,

View File

@ -625,7 +625,7 @@ uint32_t ev;
thread_data[thread_id].event = ev; thread_data[thread_id].event = ev;
} }
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
if (dcb_fake_write_ev[dcb->fd] != 0) { if (dcb_fake_write_ev[dcb->fd] != 0) {
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG, LOGFILE_DEBUG,
@ -637,7 +637,7 @@ uint32_t ev;
ev |= dcb_fake_write_ev[dcb->fd]; ev |= dcb_fake_write_ev[dcb->fd];
dcb_fake_write_ev[dcb->fd] = 0; dcb_fake_write_ev[dcb->fd] = 0;
} }
#endif #endif /* FAKE_CODE */
ss_debug(spinlock_acquire(&dcb->dcb_initlock);) ss_debug(spinlock_acquire(&dcb->dcb_initlock);)
ss_dassert(dcb->state != DCB_STATE_ALLOC); ss_dassert(dcb->state != DCB_STATE_ALLOC);
ss_dassert(dcb->state != DCB_STATE_DISCONNECTED); ss_dassert(dcb->state != DCB_STATE_DISCONNECTED);
@ -735,7 +735,7 @@ uint32_t ev;
if (ev & EPOLLERR) if (ev & EPOLLERR)
{ {
int eno = gw_getsockerrno(dcb->fd); int eno = gw_getsockerrno(dcb->fd);
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
if (eno == 0) { if (eno == 0) {
eno = dcb_fake_write_errno[dcb->fd]; eno = dcb_fake_write_errno[dcb->fd];
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
@ -748,7 +748,7 @@ uint32_t ev;
strerror(eno)))); strerror(eno))));
} }
dcb_fake_write_errno[dcb->fd] = 0; dcb_fake_write_errno[dcb->fd] = 0;
#endif #endif /* FAKE_CODE */
if (eno != 0) { if (eno != 0) {
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG, LOGFILE_DEBUG,

View File

@ -145,6 +145,7 @@ SERVICE *service;
service->filters = NULL; service->filters = NULL;
service->n_filters = 0; service->n_filters = 0;
service->weightby = 0; service->weightby = 0;
service->users = NULL;
service->resources = NULL; service->resources = NULL;
spinlock_init(&service->spin); spinlock_init(&service->spin);
spinlock_init(&service->users_table_spin); spinlock_init(&service->users_table_spin);
@ -213,42 +214,46 @@ GWPROTOCOL *funcs;
if (strcmp(port->protocol, "MySQLClient") == 0) { if (strcmp(port->protocol, "MySQLClient") == 0) {
int loaded; int loaded;
/* if (service->users == NULL) {
* Allocate specific data for MySQL users /*
* including hosts and db names * Allocate specific data for MySQL users
*/ * including hosts and db names
service->users = mysql_users_alloc(); */
service->users = mysql_users_alloc();
if ((loaded = load_mysql_users(service)) < 0) if ((loaded = load_mysql_users(service)) < 0)
{ {
LOGIF(LE, (skygw_log_write_flush( LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR, LOGFILE_ERROR,
"Error : Unable to load users from %s:%d for " "Error : Unable to load users from %s:%d for "
"service %s.", "service %s.",
port->address, port->address,
port->port, port->port,
service->name))); service->name)));
hashtable_free(service->users->data); hashtable_free(service->users->data);
free(service->users); free(service->users);
dcb_free(port->listener); dcb_free(port->listener);
port->listener = NULL; port->listener = NULL;
goto retblock; goto retblock;
}
/* At service start last update is set to USERS_REFRESH_TIME seconds earlier.
* This way MaxScale could try reloading users' just after startup
*/
service->rate_limit.last=time(NULL) - USERS_REFRESH_TIME;
service->rate_limit.nloads=1;
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"Loaded %d MySQL Users for service [%s].",
loaded, service->name)));
} }
/* At service start last update is set to USERS_REFRESH_TIME seconds earlier.
* This way MaxScale could try reloading users' just after startup
*/
service->rate_limit.last=time(NULL) - USERS_REFRESH_TIME;
service->rate_limit.nloads=1;
LOGIF(LM, (skygw_log_write(
LOGFILE_MESSAGE,
"Loaded %d MySQL Users for service [%s].",
loaded, service->name)));
} }
else else
{ {
/* Generic users table */ if (service->users == NULL) {
service->users = users_alloc(); /* Generic users table */
service->users = users_alloc();
}
} }
if ((funcs=(GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL)) if ((funcs=(GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL))

View File

@ -134,7 +134,8 @@ session_alloc(SERVICE *service, DCB *client_dcb)
service->router->newSession(service->router_instance, service->router->newSession(service->router_instance,
session); session);
if (session->router_session == NULL) { if (session->router_session == NULL)
{
/** /**
* Inform other threads that session is closing. * Inform other threads that session is closing.
*/ */
@ -153,7 +154,6 @@ session_alloc(SERVICE *service, DCB *client_dcb)
goto return_session; goto return_session;
} }
/* /*
* Pending filter chain being setup set the head of the chain to * Pending filter chain being setup set the head of the chain to
* be the router. As filters are inserted the current head will * be the router. As filters are inserted the current head will
@ -196,11 +196,12 @@ session_alloc(SERVICE *service, DCB *client_dcb)
} }
} }
spinlock_acquire(&session_spin); spinlock_acquire(&session->ses_lock);
if (session->state != SESSION_STATE_READY) if (session->state != SESSION_STATE_READY)
{ {
session_free(session); spinlock_release(&session->ses_lock);
session_free(session);
client_dcb->session = NULL; client_dcb->session = NULL;
session = NULL; session = NULL;
LOGIF(LE, (skygw_log_write_flush( LOGIF(LE, (skygw_log_write_flush(
@ -212,10 +213,13 @@ session_alloc(SERVICE *service, DCB *client_dcb)
else else
{ {
session->state = SESSION_STATE_ROUTER_READY; session->state = SESSION_STATE_ROUTER_READY;
session->next = allSessions; spinlock_release(&session->ses_lock);
spinlock_acquire(&session_spin);
session->next = allSessions;
allSessions = session; allSessions = session;
spinlock_release(&session_spin); spinlock_release(&session_spin);
atomic_add(&service->stats.n_sessions, 1);
atomic_add(&service->stats.n_sessions, 1);
atomic_add(&service->stats.n_current, 1); atomic_add(&service->stats.n_current, 1);
CHK_SESSION(session); CHK_SESSION(session);
} }

View File

@ -205,9 +205,9 @@ typedef struct dcb_callback {
typedef struct dcb { typedef struct dcb {
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
skygw_chk_t dcb_chk_top; skygw_chk_t dcb_chk_top;
bool dcb_errhandle_called;
#endif #endif
dcb_role_t dcb_role; bool dcb_errhandle_called; /*< this can be called only once */
dcb_role_t dcb_role;
SPINLOCK dcb_initlock; SPINLOCK dcb_initlock;
DCBEVENTQ evq; /**< The event queue for this DCB */ DCBEVENTQ evq; /**< The event queue for this DCB */
int fd; /**< The descriptor */ int fd; /**< The descriptor */
@ -252,14 +252,14 @@ typedef struct dcb {
#endif #endif
} DCB; } DCB;
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
unsigned char dcb_fake_write_errno[10240]; unsigned char dcb_fake_write_errno[10240];
__int32_t dcb_fake_write_ev[10240]; __int32_t dcb_fake_write_ev[10240];
bool fail_next_backend_fd; bool fail_next_backend_fd;
bool fail_next_client_fd; bool fail_next_client_fd;
int fail_next_accept; int fail_next_accept;
int fail_accept_errno; int fail_accept_errno;
#endif #endif /* FAKE_CODE */
/* A few useful macros */ /* A few useful macros */
#define DCB_SESSION(x) (x)->session #define DCB_SESSION(x) (x)->session

View File

@ -110,6 +110,10 @@ typedef enum
MONITOR_WRITE_TIMEOUT = 2 MONITOR_WRITE_TIMEOUT = 2
} monitor_timeouts_t; } monitor_timeouts_t;
#define DEFAULT_CONNECT_TIMEOUT 3
#define DEFAULT_READ_TIMEOUT 1
#define DEFAULT_WRITE_TIMEOUT 2
/** /**
* Representation of the running monitor. * Representation of the running monitor.
*/ */

View File

@ -550,7 +550,7 @@ HINT_TOKEN *tok;
else if (!inword && inquote == '\0' && **ptr == '=') else if (!inword && inquote == '\0' && **ptr == '=')
{ {
*dest = **ptr; *dest = **ptr;
*dest++; dest++;
(*ptr)++; (*ptr)++;
break; break;
} }

View File

@ -748,9 +748,12 @@ int load_filter(FILTERCHAIN* fc, CONFIG* cnf)
} }
int x; int x;
for(x = 0;x<paramc;x++){
free(fparams[x]->name); if(fparams){
free(fparams[x]->value); for(x = 0;x<paramc;x++){
free(fparams[x]->name);
free(fparams[x]->value);
}
} }
free(fparams); free(fparams);
@ -769,15 +772,18 @@ FILTERCHAIN* load_filter_module(char* str)
flt_ptr->next = instance.head; flt_ptr->next = instance.head;
} }
if((flt_ptr->instance = (FILTER_OBJECT*)load_module(str, MODULE_FILTER)) == NULL) if(flt_ptr){
{ if( (flt_ptr->instance = (FILTER_OBJECT*)load_module(str, MODULE_FILTER)) == NULL)
printf("Error: Module loading failed: %s\n",str); {
skygw_log_write(LOGFILE_ERROR,"Error: Module loading failed: %s\n",str); printf("Error: Module loading failed: %s\n",str);
free(flt_ptr->down); skygw_log_write(LOGFILE_ERROR,"Error: Module loading failed: %s\n",str);
free(flt_ptr); free(flt_ptr->down);
return NULL; free(flt_ptr);
} return NULL;
flt_ptr->name = strdup(str); }
flt_ptr->name = strdup(str);
}
return flt_ptr; return flt_ptr;
} }
@ -925,14 +931,35 @@ GWBUF* gen_packet(PACKET pkt)
int process_opts(int argc, char** argv) int process_opts(int argc, char** argv)
{ {
unsigned int fd = open_file("harness.cnf",1), buffsize = 1024; int fd, buffsize = 1024;
int rd,rdsz; int rd,rdsz, rval;
unsigned int fsize; size_t fsize;
char *buff = calloc(buffsize,sizeof(char)), *tok = NULL; char *buff = calloc(buffsize,sizeof(char)), *tok = NULL;
/**Parse 'harness.cnf' file*/ /**Parse 'harness.cnf' file*/
fsize = lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET); if(buff == NULL){
printf("Error: Call to malloc() failed.\n");
return 1;
}
if((fd = open_file("harness.cnf",1)) < 0){
printf("Failed to open configuration file.\n");
free(buff);
return 1;
}
if( (rval = lseek(fd,0,SEEK_END)) < 0 ||
lseek(fd,0,SEEK_SET) < 0){
printf("Error: Cannot seek file.\n");
close(fd);
free(buff);
return 1;
}
fsize = (size_t)rval;
instance.thrcount = 1; instance.thrcount = 1;
instance.session_count = 1; instance.session_count = 1;
rdsz = read(fd,buff,fsize); rdsz = read(fd,buff,fsize);

View File

@ -281,6 +281,7 @@ typedef struct {
* created or received */ * created or received */
unsigned long tid; /*< MySQL Thread ID, in unsigned long tid; /*< MySQL Thread ID, in
* handshake */ * handshake */
unsigned int charset; /*< MySQL character set at connect time */
#if defined(SS_DEBUG) #if defined(SS_DEBUG)
skygw_chk_t protocol_chk_tail; skygw_chk_t protocol_chk_tail;
#endif #endif

View File

@ -31,6 +31,7 @@
* 03/06/14 Mark Riddoch Add support for maintenance mode * 03/06/14 Mark Riddoch Add support for maintenance mode
* 24/06/14 Massimiliano Pinto Added depth level 0 for each node * 24/06/14 Massimiliano Pinto Added depth level 0 for each node
* 30/10/14 Massimiliano Pinto Added disableMasterFailback feature * 30/10/14 Massimiliano Pinto Added disableMasterFailback feature
* 10/11/14 Massimiliano Pinto Added setNetworkTimeout for connect,read,write
* *
* @endverbatim * @endverbatim
*/ */
@ -53,7 +54,7 @@ extern int lm_enabled_logfiles_bitmask;
static void monitorMain(void *); static void monitorMain(void *);
static char *version_str = "V1.3.0"; static char *version_str = "V1.4.0";
MODULE_INFO info = { MODULE_INFO info = {
MODULE_API_MONITOR, MODULE_API_MONITOR,
@ -69,9 +70,10 @@ static void unregisterServer(void *, SERVER *);
static void defaultUsers(void *, char *, char *); static void defaultUsers(void *, char *, char *);
static void diagnostics(DCB *, void *); static void diagnostics(DCB *, void *);
static void setInterval(void *, size_t); static void setInterval(void *, size_t);
static MONITOR_SERVERS *get_candidate_master(MONITOR_SERVERS *); static MONITOR_SERVERS *get_candidate_master(MONITOR_SERVERS *);
static MONITOR_SERVERS *set_cluster_master(MONITOR_SERVERS *, MONITOR_SERVERS *, int); static MONITOR_SERVERS *set_cluster_master(MONITOR_SERVERS *, MONITOR_SERVERS *, int);
static void disableMasterFailback(void *, int); static void disableMasterFailback(void *, int);
static void setNetworkTimeout(void *arg, int type, int value);
static MONITOR_OBJECT MyObject = { static MONITOR_OBJECT MyObject = {
startMonitor, startMonitor,
@ -81,7 +83,7 @@ static MONITOR_OBJECT MyObject = {
defaultUsers, defaultUsers,
diagnostics, diagnostics,
setInterval, setInterval,
NULL, setNetworkTimeout,
NULL, NULL,
NULL, NULL,
NULL, NULL,
@ -155,6 +157,9 @@ MYSQL_MONITOR *handle;
handle->interval = MONITOR_INTERVAL; handle->interval = MONITOR_INTERVAL;
handle->disableMasterFailback = 0; handle->disableMasterFailback = 0;
handle->master = NULL; handle->master = NULL;
handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT;
handle->read_timeout=DEFAULT_READ_TIMEOUT;
handle->write_timeout=DEFAULT_READ_TIMEOUT;
spinlock_init(&handle->lock); spinlock_init(&handle->lock);
} }
handle->tid = (THREAD)thread_start(monitorMain, handle); handle->tid = (THREAD)thread_start(monitorMain, handle);
@ -273,6 +278,9 @@ char *sep;
dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval); dcb_printf(dcb,"\tSampling interval:\t%lu milliseconds\n", handle->interval);
dcb_printf(dcb,"\tMaster Failback:\t%s\n", (handle->disableMasterFailback == 1) ? "off" : "on"); dcb_printf(dcb,"\tMaster Failback:\t%s\n", (handle->disableMasterFailback == 1) ? "off" : "on");
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", handle->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", handle->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", handle->write_timeout);
dcb_printf(dcb, "\tMonitored servers: "); dcb_printf(dcb, "\tMonitored servers: ");
db = handle->databases; db = handle->databases;
@ -310,16 +318,18 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
/** /**
* Monitor an individual server * Monitor an individual server
* *
* @param database The database to probe * @param handle The MySQL Monitor object
* @param database The database to probe
*/ */
static void static void
monitorDatabase(MONITOR_SERVERS *database, char *defaultUser, char *defaultPasswd) monitorDatabase(MYSQL_MONITOR *handle, MONITOR_SERVERS *database)
{ {
MYSQL_ROW row; MYSQL_ROW row;
MYSQL_RES *result; MYSQL_RES *result;
int num_fields; int num_fields;
int isjoined = 0; int isjoined = 0;
char *uname = defaultUser, *passwd = defaultPasswd; char *uname = handle->defaultUser;
char *passwd = handle->defaultPasswd;
unsigned long int server_version = 0; unsigned long int server_version = 0;
char *server_string; char *server_string;
@ -339,12 +349,15 @@ char *server_string;
{ {
char *dpwd = decryptPassword(passwd); char *dpwd = decryptPassword(passwd);
int rc; int rc;
int read_timeout = 1; int connect_timeout = handle->connect_timeout;
int connect_timeout = 2; int read_timeout = handle->read_timeout;
int write_timeout = handle->write_timeout;;
database->con = mysql_init(NULL); database->con = mysql_init(NULL);
rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout); rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout); rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
rc = mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
if (mysql_real_connect(database->con, database->server->name, if (mysql_real_connect(database->con, database->server->name,
uname, dpwd, NULL, database->server->port, NULL, 0) == NULL) uname, dpwd, NULL, database->server->port, NULL, 0) == NULL)
@ -487,7 +500,7 @@ int master_stickiness = handle->disableMasterFailback;
{ {
unsigned int prev_status = ptr->server->status; unsigned int prev_status = ptr->server->status;
monitorDatabase(ptr, handle->defaultUser, handle->defaultPasswd); monitorDatabase(handle, ptr);
/* clear bits for non member nodes */ /* clear bits for non member nodes */
if ( ! SERVER_IN_MAINT(ptr->server) && (ptr->server->node_id < 0 || ! SERVER_IS_JOINED(ptr->server))) { if ( ! SERVER_IN_MAINT(ptr->server) && (ptr->server->node_id < 0 || ! SERVER_IS_JOINED(ptr->server))) {
@ -662,3 +675,56 @@ MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
memcpy(&handle->disableMasterFailback, &disable, sizeof(int)); memcpy(&handle->disableMasterFailback, &disable, sizeof(int));
} }
static void
setNetworkTimeout(void *arg, int type, int value)
{
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
int max_timeout = (int)(handle->interval/1000);
int new_timeout = max_timeout -1;
if (new_timeout <= 0)
new_timeout = DEFAULT_CONNECT_TIMEOUT;
switch(type) {
case MONITOR_CONNECT_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->connect_timeout, &value, sizeof(int));
} else {
memcpy(&handle->connect_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Connect Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_READ_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->read_timeout, &value, sizeof(int));
} else {
memcpy(&handle->read_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Read Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_WRITE_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->write_timeout, &value, sizeof(int));
} else {
memcpy(&handle->write_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Write Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
default:
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Monitor setNetworkTimeout received an unsupported action type %i", type)));
break;
}
}

View File

@ -43,6 +43,7 @@
* 28/08/14 Massimiliano Pinto Added detectStaleMaster feature: previous detected master will be used again, even if the replication is stopped. * 28/08/14 Massimiliano Pinto Added detectStaleMaster feature: previous detected master will be used again, even if the replication is stopped.
* This means both IO and SQL threads are not working on slaves. * This means both IO and SQL threads are not working on slaves.
* This option is not enabled by default. * This option is not enabled by default.
* 10/11/14 Massimiliano Pinto Addition of setNetworkTimeout for connect, read, write
* *
* @endverbatim * @endverbatim
*/ */
@ -65,7 +66,7 @@ extern int lm_enabled_logfiles_bitmask;
static void monitorMain(void *); static void monitorMain(void *);
static char *version_str = "V1.3.0"; static char *version_str = "V1.4.0";
MODULE_INFO info = { MODULE_INFO info = {
MODULE_API_MONITOR, MODULE_API_MONITOR,
@ -104,7 +105,7 @@ static MONITOR_OBJECT MyObject = {
defaultUser, defaultUser,
diagnostics, diagnostics,
setInterval, setInterval,
NULL, setNetworkTimeout,
defaultId, defaultId,
replicationHeartbeat, replicationHeartbeat,
detectStaleMaster, detectStaleMaster,
@ -180,6 +181,9 @@ MYSQL_MONITOR *handle;
handle->replicationHeartbeat = 0; handle->replicationHeartbeat = 0;
handle->detectStaleMaster = 0; handle->detectStaleMaster = 0;
handle->master = NULL; handle->master = NULL;
handle->connect_timeout=DEFAULT_CONNECT_TIMEOUT;
handle->read_timeout=DEFAULT_READ_TIMEOUT;
handle->write_timeout=DEFAULT_WRITE_TIMEOUT;
spinlock_init(&handle->lock); spinlock_init(&handle->lock);
} }
handle->tid = (THREAD)thread_start(monitorMain, handle); handle->tid = (THREAD)thread_start(monitorMain, handle);
@ -326,6 +330,9 @@ char *sep;
dcb_printf(dcb,"\tMaxScale MonitorId:\t%lu\n", handle->id); dcb_printf(dcb,"\tMaxScale MonitorId:\t%lu\n", handle->id);
dcb_printf(dcb,"\tReplication lag:\t%s\n", (handle->replicationHeartbeat == 1) ? "enabled" : "disabled"); dcb_printf(dcb,"\tReplication lag:\t%s\n", (handle->replicationHeartbeat == 1) ? "enabled" : "disabled");
dcb_printf(dcb,"\tDetect Stale Master:\t%s\n", (handle->detectStaleMaster == 1) ? "enabled" : "disabled"); dcb_printf(dcb,"\tDetect Stale Master:\t%s\n", (handle->detectStaleMaster == 1) ? "enabled" : "disabled");
dcb_printf(dcb,"\tConnect Timeout:\t%i seconds\n", handle->connect_timeout);
dcb_printf(dcb,"\tRead Timeout:\t\t%i seconds\n", handle->read_timeout);
dcb_printf(dcb,"\tWrite Timeout:\t\t%i seconds\n", handle->write_timeout);
dcb_printf(dcb, "\tMonitored servers: "); dcb_printf(dcb, "\tMonitored servers: ");
db = handle->databases; db = handle->databases;
@ -381,11 +388,15 @@ char *server_string;
{ {
char *dpwd = decryptPassword(passwd); char *dpwd = decryptPassword(passwd);
int rc; int rc;
int read_timeout = 1; int connect_timeout = handle->connect_timeout;
int read_timeout = handle->read_timeout;
int write_timeout = handle->write_timeout;
database->con = mysql_init(NULL); database->con = mysql_init(NULL);
rc = mysql_options(database->con, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&connect_timeout);
rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout); rc = mysql_options(database->con, MYSQL_OPT_READ_TIMEOUT, (void *)&read_timeout);
rc = mysql_options(database->con, MYSQL_OPT_WRITE_TIMEOUT, (void *)&write_timeout);
if (mysql_real_connect(database->con, if (mysql_real_connect(database->con,
database->server->name, database->server->name,
@ -867,6 +878,13 @@ static void set_master_heartbeat(MYSQL_MONITOR *handle, MONITOR_SERVERS *databas
char heartbeat_insert_query[512]=""; char heartbeat_insert_query[512]="";
char heartbeat_purge_query[512]=""; char heartbeat_purge_query[512]="";
if (handle->master == NULL) {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"[mysql_mon]: set_master_heartbeat called without an available Master server")));
return;
}
/* create the maxscale_schema database */ /* create the maxscale_schema database */
if (mysql_query(database->con, "CREATE DATABASE IF NOT EXISTS maxscale_schema")) { if (mysql_query(database->con, "CREATE DATABASE IF NOT EXISTS maxscale_schema")) {
LOGIF(LE, (skygw_log_write_flush( LOGIF(LE, (skygw_log_write_flush(
@ -972,6 +990,13 @@ static void set_slave_heartbeat(MYSQL_MONITOR *handle, MONITOR_SERVERS *database
MYSQL_RES *result; MYSQL_RES *result;
int num_fields; int num_fields;
if (handle->master == NULL) {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"[mysql_mon]: set_slave_heartbeat called without an available Master server")));
return;
}
/* Get the master_timestamp value from maxscale_schema.replication_heartbeat table */ /* Get the master_timestamp value from maxscale_schema.replication_heartbeat table */
sprintf(select_heartbeat_query, "SELECT master_timestamp " sprintf(select_heartbeat_query, "SELECT master_timestamp "
@ -1210,11 +1235,61 @@ monitor_clear_pending_status(MONITOR_SERVERS *ptr, int bit)
/** /**
* Set the default id to use in the monitor. * Set the default id to use in the monitor.
* *
* @param arg The handle allocated by startMonitor * @param arg The handle allocated by startMonitor
* @param id The id to set in monitor struct * @param type The connect timeout type
* @param value The timeout value to set
*/ */
static void static void
setNetworkTimeout(void *arg, int type, int value) setNetworkTimeout(void *arg, int type, int value)
{ {
MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg; MYSQL_MONITOR *handle = (MYSQL_MONITOR *)arg;
int max_timeout = (int)(handle->interval/1000);
int new_timeout = max_timeout -1;
if (new_timeout <= 0)
new_timeout = DEFAULT_CONNECT_TIMEOUT;
switch(type) {
case MONITOR_CONNECT_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->connect_timeout, &value, sizeof(int));
} else {
memcpy(&handle->connect_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Connect Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_READ_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->read_timeout, &value, sizeof(int));
} else {
memcpy(&handle->read_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Read Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_WRITE_TIMEOUT:
if (value < max_timeout) {
memcpy(&handle->write_timeout, &value, sizeof(int));
} else {
memcpy(&handle->write_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Write Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
default:
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Monitor setNetworkTimeout received an unsupported action type %i", type)));
break;
}
} }

View File

@ -33,6 +33,8 @@
* 28/05/14 Massimiliano Pinto Addition of new fields in MYSQL_MONITOR struct * 28/05/14 Massimiliano Pinto Addition of new fields in MYSQL_MONITOR struct
* 24/06/14 Massimiliano Pinto Addition of master field in MYSQL_MONITOR struct and MONITOR_MAX_NUM_SLAVES * 24/06/14 Massimiliano Pinto Addition of master field in MYSQL_MONITOR struct and MONITOR_MAX_NUM_SLAVES
* 28/08/14 Massimiliano Pinto Addition of detectStaleMaster * 28/08/14 Massimiliano Pinto Addition of detectStaleMaster
* 30/10/14 Massimiliano Pinto Addition of disableMasterFailback
* 07/11/14 Massimiliano Pinto Addition of NetworkTimeout: connect, read, write
* *
* @endverbatim * @endverbatim
*/ */
@ -68,6 +70,13 @@ typedef struct {
int disableMasterFailback; /**< Monitor flag for Galera Cluster Master failback */ int disableMasterFailback; /**< Monitor flag for Galera Cluster Master failback */
MONITOR_SERVERS *master; /**< Master server for MySQL Master/Slave replication */ MONITOR_SERVERS *master; /**< Master server for MySQL Master/Slave replication */
MONITOR_SERVERS *databases; /**< Linked list of servers to monitor */ MONITOR_SERVERS *databases; /**< Linked list of servers to monitor */
int connect_timeout; /**< Connect timeout in seconds for mysql_real_connect */
int read_timeout; /**< Timeout in seconds to read from the server.
* There are retries and the total effective timeout value is three times the option value.
*/
int write_timeout; /**< Timeout in seconds for each attempt to write to the server.
* There are retries and the total effective timeout value is two times the option value.
*/
} MYSQL_MONITOR; } MYSQL_MONITOR;
#define MONITOR_RUNNING 1 #define MONITOR_RUNNING 1

View File

@ -44,6 +44,7 @@
* 12/09/2013 Massimiliano Pinto Added checks in gw_read_backend_event() for gw_read_backend_handshake * 12/09/2013 Massimiliano Pinto Added checks in gw_read_backend_event() for gw_read_backend_handshake
* 27/09/2013 Massimiliano Pinto Changed in gw_read_backend_event the check for dcb_read(), now is if rc < 0 * 27/09/2013 Massimiliano Pinto Changed in gw_read_backend_event the check for dcb_read(), now is if rc < 0
* 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support * 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support
* 10/11/2014 Massimiliano Pinto Client charset is passed to backend
* *
*/ */
#include <modinfo.h> #include <modinfo.h>
@ -378,7 +379,6 @@ static int gw_read_backend_event(DCB *dcb) {
ERRACT_REPLY_CLIENT, ERRACT_REPLY_CLIENT,
&succp); &succp);
gwbuf_free(errbuf); gwbuf_free(errbuf);
ss_dassert(!succp);
LOGIF(LD, (skygw_log_write( LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG, LOGFILE_DEBUG,
"%lu [gw_read_backend_event] " "%lu [gw_read_backend_event] "
@ -854,8 +854,12 @@ static int gw_error_backend_event(DCB *dcb)
&succp); &succp);
gwbuf_free(errbuf); gwbuf_free(errbuf);
/** There are not required backends available, close session. */ /**
if (!succp) { * If error handler fails it means that routing session can't continue
* and it must be closed. In success, only this DCB is closed.
*/
if (!succp)
{
spinlock_acquire(&session->ses_lock); spinlock_acquire(&session->ses_lock);
session->state = SESSION_STATE_STOPPING; session->state = SESSION_STATE_STOPPING;
spinlock_release(&session->ses_lock); spinlock_release(&session->ses_lock);
@ -909,6 +913,9 @@ static int gw_create_backend_connection(
/** Copy client flags to backend protocol */ /** Copy client flags to backend protocol */
protocol->client_capabilities = protocol->client_capabilities =
((MySQLProtocol *)(backend_dcb->session->client->protocol))->client_capabilities; ((MySQLProtocol *)(backend_dcb->session->client->protocol))->client_capabilities;
/** Copy client charset to backend protocol */
protocol->charset =
((MySQLProtocol *)(backend_dcb->session->client->protocol))->charset;
/*< if succeed, fd > 0, -1 otherwise */ /*< if succeed, fd > 0, -1 otherwise */
rv = gw_do_connect_to_backend(server->name, server->port, &fd); rv = gw_do_connect_to_backend(server->name, server->port, &fd);
@ -1082,8 +1089,8 @@ gw_backend_close(DCB *dcb)
mysql_protocol_done(dcb); mysql_protocol_done(dcb);
/** /**
* If session->state is set to STOPPING the client and the session must * If session->state is STOPPING, start closing client session.
* be closed too. * Otherwise only this backend connection is closed.
*/ */
if (session != NULL && session->state == SESSION_STATE_STOPPING) if (session != NULL && session->state == SESSION_STATE_STOPPING)
{ {
@ -1258,6 +1265,16 @@ static int gw_change_user(
/* get new database name */ /* get new database name */
strcpy(database, (char *)client_auth_packet); strcpy(database, (char *)client_auth_packet);
/* get character set */
if (strlen(database)) {
client_auth_packet += strlen(database) + 1;
} else {
client_auth_packet++;
}
if (client_auth_packet && *client_auth_packet)
memcpy(&backend_protocol->charset, client_auth_packet, sizeof(int));
/* save current_database name */ /* save current_database name */
strcpy(current_database, current_session->db); strcpy(current_database, current_session->db);

View File

@ -36,6 +36,7 @@
* 07/05/2014 Massimiliano Pinto Added: specific version string in server handshake * 07/05/2014 Massimiliano Pinto Added: specific version string in server handshake
* 09/09/2014 Massimiliano Pinto Added: 777 permission for socket path * 09/09/2014 Massimiliano Pinto Added: 777 permission for socket path
* 13/10/2014 Massimiliano Pinto Added: dbname authentication check * 13/10/2014 Massimiliano Pinto Added: dbname authentication check
* 10/11/2014 Massimiliano Pinto Added: client charset added to protocol struct
* *
*/ */
#include <skygw_utils.h> #include <skygw_utils.h>
@ -444,6 +445,9 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
return 1; return 1;
} }
/* get charset */
memcpy(&protocol->charset, client_auth_packet + 4 + 4 + 4, sizeof (int));
/* get the auth token len */ /* get the auth token len */
memcpy(&auth_token_len, memcpy(&auth_token_len,
client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1,
@ -836,9 +840,6 @@ int gw_read_client_event(
} }
else else
{ {
GWBUF* errbuf;
bool succp;
modutil_send_mysql_err_packet(dcb, modutil_send_mysql_err_packet(dcb,
1, 1,
0, 0,
@ -850,7 +851,6 @@ int gw_read_client_event(
"Error : Routing the query failed. " "Error : Routing the query failed. "
"Session will be closed."))); "Session will be closed.")));
dcb_close(dcb); dcb_close(dcb);
} }
} }
@ -1109,7 +1109,7 @@ int gw_MySQLAccept(DCB *listener)
retry_accept: retry_accept:
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
if (fail_next_accept > 0) if (fail_next_accept > 0)
{ {
c_sock = -1; c_sock = -1;
@ -1117,16 +1117,16 @@ int gw_MySQLAccept(DCB *listener)
fail_next_accept -= 1; fail_next_accept -= 1;
} else { } else {
fail_accept_errno = 0; fail_accept_errno = 0;
#endif /* SS_DEBUG */ #endif /* FAKE_CODE */
// new connection from client // new connection from client
c_sock = accept(listener->fd, c_sock = accept(listener->fd,
(struct sockaddr *) &client_conn, (struct sockaddr *) &client_conn,
&client_len); &client_len);
eno = errno; eno = errno;
errno = 0; errno = 0;
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
} }
#endif /* SS_DEBUG */ #endif /* FAKE_CODE */
if (c_sock == -1) { if (c_sock == -1) {
@ -1363,7 +1363,6 @@ gw_client_close(DCB *dcb)
SESSION* session; SESSION* session;
ROUTER_OBJECT* router; ROUTER_OBJECT* router;
void* router_instance; void* router_instance;
void* rsession;
#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 ||
@ -1389,13 +1388,22 @@ gw_client_close(DCB *dcb)
{ {
session->state = SESSION_STATE_STOPPING; session->state = SESSION_STATE_STOPPING;
} }
spinlock_release(&session->ses_lock);
router = session->service->router;
router_instance = session->service->router_instance; router_instance = session->service->router_instance;
rsession = session->router_session; router = session->service->router;
/** Close router session and all its connections */ /**
router->closeSession(router_instance, rsession); * If router session is being created concurrently router
* session might be NULL and it shouldn't be closed.
*/
if (session->router_session != NULL)
{
spinlock_release(&session->ses_lock);
/** Close router session and all its connections */
router->closeSession(router_instance, session->router_session);
}
else
{
spinlock_release(&session->ses_lock);
}
} }
return 1; return 1;
} }

View File

@ -35,6 +35,7 @@
* x.y.z.%, x.y.%.%, x.%.%.% * x.y.z.%, x.y.%.%, x.%.%.%
* 03/10/2014 Massimiliano Pinto Added netmask for wildcard in IPv4 hosts. * 03/10/2014 Massimiliano Pinto Added netmask for wildcard in IPv4 hosts.
* 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support * 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support
* 10/11/2014 Massimiliano Pinto Charset at connect is passed to backend during authentication
* *
*/ */
@ -563,6 +564,7 @@ int gw_send_authentication_to_backend(
char *curr_db = NULL; char *curr_db = NULL;
uint8_t *curr_passwd = NULL; uint8_t *curr_passwd = NULL;
unsigned int charset;
if (strlen(dbname)) if (strlen(dbname))
curr_db = dbname; curr_db = dbname;
@ -574,7 +576,10 @@ int gw_send_authentication_to_backend(
final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities); final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities);
/** Copy client's flags to backend */ /** Copy client's flags to backend */
final_capabilities |= conn->client_capabilities;; final_capabilities |= conn->client_capabilities;
/* get charset the client sent and use it for connection auth */
charset = conn->charset;
if (compress) { if (compress) {
final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS; final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS;
@ -668,7 +673,7 @@ int gw_send_authentication_to_backend(
// set the charset // set the charset
payload += 4; payload += 4;
*payload = '\x08'; *payload = charset;
payload++; payload++;
@ -768,9 +773,43 @@ int gw_do_connect_to_backend(
setipaddress(&serv_addr.sin_addr, host); setipaddress(&serv_addr.sin_addr, host);
serv_addr.sin_port = htons(port); serv_addr.sin_port = htons(port);
bufsize = GW_BACKEND_SO_SNDBUF; bufsize = GW_BACKEND_SO_SNDBUF;
setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
if(setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) != 0)
{
int eno = errno;
errno = 0;
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error: Failed to set socket options "
"%s:%d failed.\n\t\t Socket configuration failed "
"due %d, %s.",
host,
port,
eno,
strerror(eno))));
rv = -1;
goto return_rv;
}
bufsize = GW_BACKEND_SO_RCVBUF; bufsize = GW_BACKEND_SO_RCVBUF;
setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
if(setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) != 0)
{
int eno = errno;
errno = 0;
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error: Failed to set socket options "
"%s:%d failed.\n\t\t Socket configuration failed "
"due %d, %s.",
host,
port,
eno,
strerror(eno))));
rv = -1;
goto return_rv;
}
/* set socket to as non-blocking here */ /* set socket to as non-blocking here */
setnonblocking(so); setnonblocking(so);
rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
@ -1050,6 +1089,7 @@ int gw_send_change_user_to_backend(
char *curr_db = NULL; char *curr_db = NULL;
uint8_t *curr_passwd = NULL; uint8_t *curr_passwd = NULL;
unsigned int charset;
if (strlen(dbname)) if (strlen(dbname))
curr_db = dbname; curr_db = dbname;
@ -1062,7 +1102,10 @@ int gw_send_change_user_to_backend(
final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities); final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities);
/** Copy client's flags to backend */ /** Copy client's flags to backend */
final_capabilities |= conn->client_capabilities;; final_capabilities |= conn->client_capabilities;
/* get charset the client sent and use it for connection auth */
charset = conn->charset;
if (compress) { if (compress) {
final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS; final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS;
@ -1188,7 +1231,7 @@ int gw_send_change_user_to_backend(
} }
// set the charset, 2 bytes!!!! // set the charset, 2 bytes!!!!
*payload = '\x08'; *payload = charset;
payload++; payload++;
*payload = '\x00'; *payload = '\x00';
payload++; payload++;

View File

@ -414,7 +414,7 @@ struct subcommand disableoptions[] = {
} }
}; };
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
static void fail_backendfd(void); static void fail_backendfd(void);
static void fail_clientfd(void); static void fail_clientfd(void);
@ -456,7 +456,7 @@ struct subcommand failoptions[] = {
{0, 0, 0} {0, 0, 0}
} }
}; };
#endif /* SS_DEBUG */ #endif /* FAKE_CODE */
static void telnetdAddUser(DCB *, char *, char *); static void telnetdAddUser(DCB *, char *, char *);
/** /**
@ -502,9 +502,9 @@ static struct {
{ "clear", clearoptions }, { "clear", clearoptions },
{ "disable", disableoptions }, { "disable", disableoptions },
{ "enable", enableoptions }, { "enable", enableoptions },
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
{ "fail", failoptions }, { "fail", failoptions },
#endif #endif /* FAKE_CODE */
{ "list", listoptions }, { "list", listoptions },
{ "reload", reloadoptions }, { "reload", reloadoptions },
{ "remove", removeoptions }, { "remove", removeoptions },
@ -1113,7 +1113,7 @@ static void disable_log_action(DCB *dcb, char *arg1) {
skygw_log_disable(type); skygw_log_disable(type);
} }
#if defined(SS_DEBUG) #if defined(FAKE_CODE)
static void fail_backendfd(void) static void fail_backendfd(void)
{ {
fail_next_backend_fd = true; fail_next_backend_fd = true;
@ -1157,4 +1157,4 @@ static void fail_accept(
return ; return ;
} }
} }
#endif #endif /* FAKE_CODE */

View File

@ -828,6 +828,17 @@ static void handleError(
SESSION *session = backend_dcb->session; SESSION *session = backend_dcb->session;
session_state_t sesstate; session_state_t sesstate;
/** Don't handle same error twice on same DCB */
if (backend_dcb->dcb_errhandle_called)
{
/** we optimistically assume that previous call succeed */
*succp = true;
return;
}
else
{
backend_dcb->dcb_errhandle_called = true;
}
spinlock_acquire(&session->ses_lock); spinlock_acquire(&session->ses_lock);
sesstate = session->state; sesstate = session->state;
client_dcb = session->client; client_dcb = session->client;

View File

@ -830,8 +830,16 @@ static void* newSession(
* Find a backend servers to connect to. * Find a backend servers to connect to.
* This command requires that rsession's lock is held. * This command requires that rsession's lock is held.
*/ */
rses_begin_locked_router_action(client_rses);
succp = rses_begin_locked_router_action(client_rses);
if(!succp)
{
free(client_rses->rses_backend_ref);
free(client_rses);
client_rses = NULL;
goto return_rses;
}
succp = select_connect_backend_servers(&master_ref, succp = select_connect_backend_servers(&master_ref,
backend_ref, backend_ref,
router_nservers, router_nservers,
@ -1029,6 +1037,9 @@ static void freeSession(
/** /**
* Provide the router with a pointer to a suitable backend dcb. * Provide the router with a pointer to a suitable backend dcb.
*
* As of Nov. 2014, slave which has least connections is always chosen.
*
* Detect failures in server statuses and reselect backends if necessary. * Detect failures in server statuses and reselect backends if necessary.
* If name is specified, server name becomes primary selection criteria. * If name is specified, server name becomes primary selection criteria.
* *
@ -1610,8 +1621,12 @@ void check_create_tmp_table(
rses_prop_tmp->rses_prop_type = RSES_PROP_TYPE_TMPTABLES; rses_prop_tmp->rses_prop_type = RSES_PROP_TYPE_TMPTABLES;
router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES] = rses_prop_tmp; router_cli_ses->rses_properties[RSES_PROP_TYPE_TMPTABLES] = rses_prop_tmp;
} }
else
{
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,"Error : Call to malloc() failed.")));
}
} }
if(rses_prop_tmp){
if (rses_prop_tmp->rses_prop_data.temp_tables == NULL) if (rses_prop_tmp->rses_prop_data.temp_tables == NULL)
{ {
h = hashtable_alloc(7, hashkeyfun, hashcmpfun); h = hashtable_alloc(7, hashkeyfun, hashcmpfun);
@ -1619,10 +1634,13 @@ void check_create_tmp_table(
if (h != NULL) if (h != NULL)
{ {
rses_prop_tmp->rses_prop_data.temp_tables = h; rses_prop_tmp->rses_prop_data.temp_tables = h;
} }else{
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,"Error : Failed to allocate a new hashtable.")));
}
} }
if (hkey && if (hkey && rses_prop_tmp->rses_prop_data.temp_tables &&
hashtable_add(rses_prop_tmp->rses_prop_data.temp_tables, hashtable_add(rses_prop_tmp->rses_prop_data.temp_tables,
(void *)hkey, (void *)hkey,
(void *)is_temp) == 0) /*< Conflict in hash table */ (void *)is_temp) == 0) /*< Conflict in hash table */
@ -1647,6 +1665,8 @@ void check_create_tmp_table(
} }
} }
#endif #endif
}
free(hkey); free(hkey);
free(tblname); free(tblname);
} }
@ -2074,14 +2094,11 @@ static int routeQuery(
"route to master " "route to master "
"but couldn't find " "but couldn't find "
"master in a " "master in a "
"suitable state " "suitable state.")));
"failed.")));
} }
/** /**
* Master has changed. Set the dcb pointer NULL and * Master has changed. Return with error indicator.
* return with error indicator.
*/ */
router_cli_ses->rses_master_ref->bref_dcb = NULL;
rses_end_locked_router_action(router_cli_ses); rses_end_locked_router_action(router_cli_ses);
succp = false; succp = false;
ret = 0; ret = 0;
@ -2655,7 +2672,7 @@ static bool select_connect_backend_servers(
const int min_nslaves = 0; /*< not configurable at the time */ const int min_nslaves = 0; /*< not configurable at the time */
bool is_synced_master; bool is_synced_master;
int (*p)(const void *, const void *); int (*p)(const void *, const void *);
BACKEND* master_host = NULL; BACKEND* master_host;
if (p_master_ref == NULL || backend_ref == NULL) if (p_master_ref == NULL || backend_ref == NULL)
{ {
@ -2667,46 +2684,32 @@ static bool select_connect_backend_servers(
/* get the root Master */ /* get the root Master */
master_host = get_root_master(backend_ref, router_nservers); master_host = get_root_master(backend_ref, router_nservers);
/** /**
* Master is already chosen and connected. It means that the function * Existing session : master is already chosen and connected.
* was called from error handling function or from some other similar * The function was called because new slave must be selected to replace
* function where session was already established but new slaves needed * failed one.
* to be selected.
*/ */
if (*p_master_ref != NULL && if (*p_master_ref != NULL)
BREF_IS_IN_USE((*p_master_ref))) {
{
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"%lu [select_connect_backend_servers] Master %p fd %d found.",
pthread_self(),
(*p_master_ref)->bref_dcb,
(*p_master_ref)->bref_dcb->fd)));
master_found = true;
master_connected = true;
/** /**
* Ensure that *p_master_ref and master_host point to same backend * Ensure that backend reference is in use, stored master is
* and it has a master role. * still current root master.
*/ */
ss_dassert(master_host && if (!BREF_IS_IN_USE((*p_master_ref)) ||
((*p_master_ref)->bref_backend->backend_server == !SERVER_IS_MASTER((*p_master_ref)->bref_backend->backend_server) ||
master_host->backend_server) && master_host != (*p_master_ref)->bref_backend)
(master_host->backend_server->status & {
(SERVER_MASTER|SERVER_MAINT)) == SERVER_MASTER); succp = false;
} goto return_succp;
/** New session or master failure case */ }
master_found = true;
master_connected = true;
}
/**
* New session : select master and slaves
*/
else else
{ {
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"%lu [select_connect_backend_servers] Session %p doesn't "
"currently have a master chosen. Proceeding to master "
"selection.",
pthread_self(),
session)));
master_found = false; master_found = false;
master_connected = false; master_connected = false;
} }
@ -2745,11 +2748,6 @@ static bool select_connect_backend_servers(
b->backend_conn_count))); b->backend_conn_count)));
} }
#endif #endif
/* assert with master_host */
ss_dassert(!master_connected ||
(master_host &&
((*p_master_ref)->bref_backend->backend_server == master_host->backend_server) &&
SERVER_MASTER));
/** /**
* Sort the pointer list to servers according to connection counts. As * Sort the pointer list to servers according to connection counts. As
* a consequence those backends having least connections are in the * a consequence those backends having least connections are in the
@ -2840,8 +2838,10 @@ static bool select_connect_backend_servers(
(max_slave_rlag == MAX_RLAG_UNDEFINED || (max_slave_rlag == MAX_RLAG_UNDEFINED ||
(b->backend_server->rlag != MAX_RLAG_NOT_AVAILABLE && (b->backend_server->rlag != MAX_RLAG_NOT_AVAILABLE &&
b->backend_server->rlag <= max_slave_rlag)) && b->backend_server->rlag <= max_slave_rlag)) &&
(SERVER_IS_SLAVE(b->backend_server) || SERVER_IS_RELAY_SERVER(b->backend_server)) && (SERVER_IS_SLAVE(b->backend_server) ||
(master_host != NULL && (b->backend_server != master_host->backend_server))) SERVER_IS_RELAY_SERVER(b->backend_server)) &&
(master_host != NULL &&
(b->backend_server != master_host->backend_server)))
{ {
slaves_found += 1; slaves_found += 1;
@ -2903,6 +2903,12 @@ static bool select_connect_backend_servers(
else if (master_host && else if (master_host &&
(b->backend_server == master_host->backend_server)) (b->backend_server == master_host->backend_server))
{ {
/**
* *p_master_ref must be assigned with this
* backend_ref pointer because its original value
* may have been lost when backend references were
* sorted (qsort).
*/
*p_master_ref = &backend_ref[i]; *p_master_ref = &backend_ref[i];
if (master_connected) if (master_connected)
@ -4072,7 +4078,6 @@ static void rwsplit_process_router_options(
* Even if succp == true connecting to new slave may have failed. succp is to * Even if succp == true connecting to new slave may have failed. succp is to
* tell whether router has enough master/slave connections to continue work. * tell whether router has enough master/slave connections to continue work.
*/ */
static void handleError ( static void handleError (
ROUTER* instance, ROUTER* instance,
void* router_session, void* router_session,
@ -4086,10 +4091,17 @@ static void handleError (
ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES *)router_session; ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES *)router_session;
CHK_DCB(backend_dcb); CHK_DCB(backend_dcb);
#if defined(SS_DEBUG) /** Don't handle same error twice on same DCB */
ss_dassert(!backend_dcb->dcb_errhandle_called); if (backend_dcb->dcb_errhandle_called)
backend_dcb->dcb_errhandle_called = true; {
#endif /** we optimistically assume that previous call succeed */
*succp = true;
return;
}
else
{
backend_dcb->dcb_errhandle_called = true;
}
session = backend_dcb->session; session = backend_dcb->session;
if (session != NULL) if (session != NULL)
@ -4107,7 +4119,8 @@ static void handleError (
return; return;
} }
if (rses->rses_master_ref->bref_dcb == backend_dcb) if (rses->rses_master_ref->bref_dcb == backend_dcb &&
!SERVER_IS_MASTER(rses->rses_master_ref->bref_backend->backend_server))
{ {
/** Master failed, can't recover */ /** Master failed, can't recover */
LOGIF(LE, (skygw_log_write_flush( LOGIF(LE, (skygw_log_write_flush(
@ -4206,6 +4219,11 @@ static bool handle_error_new_connection(
} }
CHK_BACKEND_REF(bref); CHK_BACKEND_REF(bref);
/**
* If query was sent through the bref and it is waiting for reply from
* the backend server it is necessary to send an error to the client
* because it is waiting for reply.
*/
if (BREF_IS_WAITING_RESULT(bref)) if (BREF_IS_WAITING_RESULT(bref))
{ {
DCB* client_dcb; DCB* client_dcb;
@ -4473,6 +4491,10 @@ static backend_ref_t* get_bref_from_dcb(
return bref; return bref;
} }
/**
* Calls hang-up function for DCB if it is not both running and in
* master/slave/joined/ndb role. Called by DCB's callback routine.
*/
static int router_handle_state_switch( static int router_handle_state_switch(
DCB* dcb, DCB* dcb,
DCB_REASON reason, DCB_REASON reason,
@ -4513,6 +4535,7 @@ return_rc:
return rc; return rc;
} }
static sescmd_cursor_t* backend_ref_get_sescmd_cursor ( static sescmd_cursor_t* backend_ref_get_sescmd_cursor (
backend_ref_t* bref) backend_ref_t* bref)
{ {
@ -4634,7 +4657,7 @@ static BACKEND *get_root_master(
* Servers are checked even if they are in 'maintenance' * Servers are checked even if they are in 'maintenance'
* *
* @param rses pointer to router session * @param rses pointer to router session
* @return pointer to backend reference of the root master * @return pointer to backend reference of the root master or NULL
* *
*/ */
static backend_ref_t* get_root_master_bref( static backend_ref_t* get_root_master_bref(
@ -4664,6 +4687,14 @@ static backend_ref_t* get_root_master_bref(
bref++; bref++;
i += 1; i += 1;
} }
if (candidate_bref == NULL)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Could not find master among the backend "
"servers. Previous master state : %s",
STRSRVSTATUS(BREFSRV(rses->rses_master_ref)))));
}
return candidate_bref; return candidate_bref;
} }

View File

@ -1,6 +1,6 @@
if(MYSQLCLIENT_FOUND) if(MYSQLCLIENT_FOUND)
add_executable(testconnect testconnect.c) add_executable(testconnect testconnect.c)
message(STATUS "Linking against: ${MYSQLCLIENT_LIBRARIES}") message(STATUS "Linking against: ${MYSQLCLIENT_LIBRARIES}")
target_link_libraries(testconnect ${MYSQLCLIENT_LIBRARIES} ssl crypto dl z m) target_link_libraries(testconnect ${MYSQLCLIENT_LIBRARIES} ssl crypto dl z m rt pthread)
add_test(NAME ReadConnRouterLoginTest COMMAND $<TARGET_FILE:testconnect> 10000 ${TEST_HOST} ${MASTER_PORT} ${TEST_HOST} ${TEST_PORT} 1.10) add_test(NAME ReadConnRouterLoginTest COMMAND $<TARGET_FILE:testconnect> 10000 ${TEST_HOST} ${MASTER_PORT} ${TEST_HOST} ${TEST_PORT} 1.10)
endif() endif()

View File

@ -4,24 +4,40 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <sys/time.h>
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
MYSQL* server; MYSQL* server;
char *host; char *host = NULL, *str_baseline = NULL,*str_test = NULL, *errmsg = NULL;
unsigned int port; unsigned int port;
int rval, iterations,i; int rval, iterations,i;
clock_t begin,end; clock_t begin,end;
double baseline,test, ratio, result, minimum; size_t offset;
struct timeval real_begin,real_end,real_baseline,real_test;
time_t time;
double baseline, test, ratio, result;
if(argc < 7){ if(argc < 7){
fprintf(stderr,"Usage: %s <iterations> <baseline host> <baseline port> <test host> <test port> <max result ratio>\n",argv[0]); fprintf(stderr,"Usage: %s <iterations> <baseline host> <baseline port> <test host> <test port> <max result ratio>\n",argv[0]);
fprintf(stderr,"The ratio is measured as:\ntest CPU time / baseline CPU time\n"); fprintf(stderr,"The ratio is measured as:\ntest time / baseline time\n");
fprintf(stderr,"The test fails if this ratio is exceeded.\n"); fprintf(stderr,"The test fails if this ratio is exceeded.\n");
return 1; return 1;
} }
;
if((str_baseline = calloc(256,sizeof(char))) == NULL){
return 1;
}
if((str_test = calloc(256,sizeof(char))) == NULL){
free(str_baseline);
return 1;
}
iterations = atoi(argv[1]); iterations = atoi(argv[1]);
host = strdup(argv[2]); host = strdup(argv[2]);
port = atoi(argv[3]); port = atoi(argv[3]);
@ -35,24 +51,36 @@ int main(int argc, char** argv)
/**Testing direct connection to master*/ /**Testing direct connection to master*/
printf("Connecting to MySQL server through %s:%d.\n",host,port); printf("Connecting to MySQL server through %s:%d.\n",host,port);
gettimeofday(&real_begin,NULL);
begin = clock(); begin = clock();
if((server = mysql_init(NULL)) == NULL){
return 1;
}
if(mysql_real_connect(server,host,"maxuser","maxpwd",NULL,port,NULL,0) == NULL){
rval = 1;
printf( "Failed to connect to database: Error: %s\n",
mysql_error(server));
goto report;
}
for(i = 0;i<iterations;i++) for(i = 0;i<iterations;i++)
{ {
if((server = mysql_init(NULL)) == NULL){ if(mysql_change_user(server,"maxuser","maxpwd",NULL)){
return 1;
}
if(mysql_real_connect(server,host,"maxuser","maxpwd",NULL,port,NULL,0) == NULL){
fprintf(stderr, "Failed to connect to database: Error: %s\n",
mysql_error(server));
rval = 1; rval = 1;
break; printf( "Failed to change user: Error: %s\n",
mysql_error(server));
goto report;
} }
mysql_close(server);
} }
mysql_close(server);
end = clock(); end = clock();
gettimeofday(&real_end,NULL);
baseline = (double)(end - begin)/CLOCKS_PER_SEC; baseline = (double)(end - begin)/CLOCKS_PER_SEC;
timersub(&real_end,&real_begin,&real_baseline);
free(host); free(host);
host = strdup(argv[4]); host = strdup(argv[4]);
@ -61,37 +89,73 @@ int main(int argc, char** argv)
/**Testing connection to master through MaxScale*/ /**Testing connection to master through MaxScale*/
printf("Connecting to MySQL server through %s:%d.\n",host,port); printf("Connecting to MySQL server through %s:%d.\n",host,port);
gettimeofday(&real_begin,NULL);
begin = clock(); begin = clock();
if((server = mysql_init(NULL)) == NULL){
return 1;
}
if(mysql_real_connect(server,host,"maxuser","maxpwd",NULL,port,NULL,0) == NULL){
rval = 1;
printf("Failed to connect to database: Error: %s\n",
mysql_error(server));
goto report;
}
for(i = 0;i<iterations;i++) for(i = 0;i<iterations;i++)
{ {
if((server = mysql_init(NULL)) == NULL){ if(mysql_change_user(server,"maxuser","maxpwd",NULL)){
return 1;
}
if(mysql_real_connect(server,host,"maxuser","maxpwd",NULL,port,NULL,0) == NULL){
rval = 1; rval = 1;
fprintf(stderr, "Failed to connect to database: Error: %s\n", printf("Failed to change user: Error: %s\n",
mysql_error(server)); mysql_error(server));
break; goto report;
} }
mysql_close(server);
} }
mysql_close(server);
end = clock(); end = clock();
gettimeofday(&real_end,NULL);
test = (double)(end - begin)/CLOCKS_PER_SEC; test = (double)(end - begin)/CLOCKS_PER_SEC;
timersub(&real_end,&real_begin,&real_test);
printf("CPU time used in seconds:\nDirect connection: %f\nThrough MaxScale: %f\n",baseline,test); report:
result = test / baseline;
if(rval){ if(rval){
printf("Test failed: Errors during test run.");
}else if(result > ratio){
printf("Test failed: CPU time ratio was %f which exceeded the limit of %f.\n", result, ratio);
rval = 1;
}else{
printf("Test passed: CPU time ratio was %f.\n",result);
}
printf("\nTest failed: Errors during test run.\n");
}else{
struct tm *tm;
time = real_baseline.tv_sec;
tm = localtime(&time);
offset = strftime(str_baseline,256*sizeof(char),"%S",tm);
sprintf(str_baseline + offset,".%06d",(int)real_baseline.tv_usec);
time = real_test.tv_sec;
tm = localtime(&time);
offset = strftime(str_test,256*sizeof(char),"%S",tm);
sprintf(str_test + offset,".%06d",(int)real_test.tv_usec);
printf("\n\tCPU time in seconds\n\nDirect connection: %f\nThrough MaxScale: %f\n",baseline,test);
printf("\n\tReal time in seconds\n\nDirect connection: %s\nThrough MaxScale: %s\n",str_baseline,str_test);
double base_res = real_baseline.tv_sec + (real_baseline.tv_usec / 1000000.0);
double test_res = real_test.tv_sec + (real_test.tv_usec / 1000000.0);
result = test_res/base_res;
if(result > ratio){
printf("\nTest failed: Time ratio was %f which exceeded the limit of %f.\n", result, ratio);
rval = 1;
}else{
printf("\nTest passed: Time ratio was %f.\n",result);
}
}
free(str_baseline);
free(str_test);
free(host); free(host);
free(errmsg);
return rval; return rval;
} }

View File

@ -263,6 +263,9 @@ typedef enum skygw_chk_t {
(SERVER_IS_RELAY_SERVER(s) ? "RUNNING RELAY" : \ (SERVER_IS_RELAY_SERVER(s) ? "RUNNING RELAY" : \
(SERVER_IS_RUNNING(s) ? "RUNNING (only)" : "NO STATUS"))))))) (SERVER_IS_RUNNING(s) ? "RUNNING (only)" : "NO STATUS")))))))
#define BREFSRV(b) (b->bref_backend->backend_server)
#define STRHINTTYPE(t) (t == HINT_ROUTE_TO_MASTER ? "HINT_ROUTE_TO_MASTER" : \ #define STRHINTTYPE(t) (t == HINT_ROUTE_TO_MASTER ? "HINT_ROUTE_TO_MASTER" : \
((t) == HINT_ROUTE_TO_SLAVE ? "HINT_ROUTE_TO_SLAVE" : \ ((t) == HINT_ROUTE_TO_SLAVE ? "HINT_ROUTE_TO_SLAVE" : \
((t) == HINT_ROUTE_TO_NAMED_SERVER ? "HINT_ROUTE_TO_NAMED_SERVER" : \ ((t) == HINT_ROUTE_TO_NAMED_SERVER ? "HINT_ROUTE_TO_NAMED_SERVER" : \

View File

@ -1749,14 +1749,23 @@ return_succp:
return succp; return succp;
} }
/**
bool skygw_file_write( * Write data to a file.
*
* @param file write target
* @param data pointer to contiguous memory buffer
* @param nbytes amount of bytes to be written
* @param flush ensure that write is permanent
*
* @return 0 if succeed, errno if failed.
*/
int skygw_file_write(
skygw_file_t* file, skygw_file_t* file,
void* data, void* data,
size_t nbytes, size_t nbytes,
bool flush) bool flush)
{ {
bool succp = false; int rc;
#if !defined(LAPTOP_TEST) #if !defined(LAPTOP_TEST)
int err = 0; int err = 0;
size_t nwritten; size_t nwritten;
@ -1771,13 +1780,14 @@ bool skygw_file_write(
nwritten = fwrite(data, nbytes, 1, file->sf_file); nwritten = fwrite(data, nbytes, 1, file->sf_file);
if (nwritten != 1) { if (nwritten != 1) {
rc = errno;
perror("Logfile write.\n"); perror("Logfile write.\n");
fprintf(stderr, fprintf(stderr,
"* Writing %ld bytes, %s to %s failed.\n", "* Writing %ld bytes,\n%s\n to %s failed.\n",
nbytes, nbytes,
(char *)data, (char *)data,
file->sf_fname); file->sf_fname);
goto return_succp; goto return_rc;
} }
writecount += 1; writecount += 1;
@ -1789,10 +1799,10 @@ bool skygw_file_write(
writecount = 0; writecount = 0;
} }
#endif #endif
succp = true; rc = 0;
CHK_FILE(file); CHK_FILE(file);
return_succp: return_rc:
return succp; return rc;
} }
skygw_file_t* skygw_file_init( skygw_file_t* skygw_file_init(

View File

@ -146,7 +146,7 @@ EXTERN_C_BLOCK_END
/** Skygw file routines */ /** Skygw file routines */
skygw_file_t* skygw_file_init(char* fname, char* symlinkname); skygw_file_t* skygw_file_init(char* fname, char* symlinkname);
void skygw_file_done(skygw_file_t* file); void skygw_file_done(skygw_file_t* file);
bool skygw_file_write( int skygw_file_write(
skygw_file_t* file, skygw_file_t* file,
void* data, void* data,
size_t nbytes, size_t nbytes,