Merge remote-tracking branch 'origin/develop' into MXS-122
Conflicts: server/core/dcb.c
This commit is contained in:
@ -19,7 +19,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#define _XOPEN_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <crypt.h>
|
||||
#include <users.h>
|
||||
|
||||
@ -311,7 +311,7 @@ if((monitorhash = hashtable_alloc(5,simple_str_hash,strcmp)) == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
|
||||
hashtable_memory_fns(monitorhash,(HASHMEMORYFN)strdup,NULL,(HASHMEMORYFN)free,NULL);
|
||||
/**
|
||||
* Process the data and create the services and servers defined
|
||||
* in the data.
|
||||
@ -429,7 +429,7 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
|
||||
|
||||
/** Add the 5.5.5- string to the start of the version string if
|
||||
* the version string starts with "10.".
|
||||
* This mimics MariaDB 10.0 behavior which adds 5.5.5- for backwards compatibility. */
|
||||
* This mimics MariaDB 10.0 replication which adds 5.5.5- for backwards compatibility. */
|
||||
if(strncmp(version_string,"10.",3) == 0)
|
||||
{
|
||||
((SERVICE *)(obj->element))->version_string = malloc((strlen(version_string) +
|
||||
@ -940,7 +940,7 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
|
||||
/* if id is not set, do it now */
|
||||
if (gateway.id == 0) {
|
||||
setipaddress(&serv_addr.sin_addr, (address == NULL) ? "0.0.0.0" : address);
|
||||
gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + port != NULL ? atoi(port) : 0 + getpid());
|
||||
gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + (port != NULL ? atoi(port) : 0 + getpid()));
|
||||
}
|
||||
|
||||
if (service && socket && protocol) {
|
||||
|
||||
@ -974,18 +974,10 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
}
|
||||
}
|
||||
|
||||
if(havedb && wildcard_db_grant(dbnm))
|
||||
if(havedb && wildcard_db_grant(dbnm) && service->optimize_wildcard)
|
||||
{
|
||||
if(service->optimize_wildcard)
|
||||
{
|
||||
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
|
||||
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,dbnm,rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Use ANYDB for wildcard grants */
|
||||
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, "Y", NULL);
|
||||
}
|
||||
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
|
||||
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,dbnm,rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1041,8 +1033,8 @@ getAllUsers(SERVICE *service, USERS *users)
|
||||
|
||||
} else if(rc == -1) {
|
||||
/** Duplicate user*/
|
||||
LOGIF(LE,(skygw_log_write(LT|LE,
|
||||
"Warning: Duplicate MySQL user found for service [%s]: %s@%s%s%s",
|
||||
LOGIF(LT,(skygw_log_write(LT,
|
||||
"Duplicate MySQL user found for service [%s]: %s@%s%s%s",
|
||||
service->name,
|
||||
row[0],row[1],havedb?" for database: ":"",
|
||||
havedb ?dbnm:"")));
|
||||
@ -1706,6 +1698,41 @@ static int uh_cmpfun( void* v1, void* v2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(hu2->resource && strlen(hu2->resource) && strchr(hu2->resource,'%') != NULL)
|
||||
{
|
||||
regex_t re;
|
||||
char db[MYSQL_DATABASE_MAXLEN*2 +1];
|
||||
strcpy(db,hu2->resource);
|
||||
int len = strlen(db);
|
||||
char* ptr = strrchr(db,'%');
|
||||
|
||||
if(ptr == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(ptr)
|
||||
{
|
||||
memmove(ptr+1,ptr,(len - (ptr - db)) + 1);
|
||||
*ptr = '.';
|
||||
*(ptr + 1) = '*';
|
||||
len = strlen(db);
|
||||
ptr = strrchr(db,'%');
|
||||
}
|
||||
|
||||
if((regcomp(&re,db,REG_ICASE|REG_NOSUB)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(regexec(&re,hu1->resource,0,NULL,0) == 0)
|
||||
{
|
||||
regfree(&re);
|
||||
return 0;
|
||||
}
|
||||
regfree(&re);
|
||||
}
|
||||
|
||||
/* no matches, deny auth */
|
||||
return 1;
|
||||
}
|
||||
@ -1815,18 +1842,6 @@ char *mysql_format_user_entry(void *data)
|
||||
return mysql_user;
|
||||
}
|
||||
|
||||
/*
|
||||
* The hash function we use for storing MySQL database names.
|
||||
*
|
||||
* @param key The key value
|
||||
* @return The hash key
|
||||
*/
|
||||
int
|
||||
resource_hash(char *key)
|
||||
{
|
||||
return (*key + *(key + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the resources table
|
||||
*
|
||||
@ -1850,7 +1865,7 @@ resource_alloc()
|
||||
{
|
||||
HASHTABLE *resources;
|
||||
|
||||
if ((resources = hashtable_alloc(10, resource_hash, strcmp)) == NULL)
|
||||
if ((resources = hashtable_alloc(10, simple_str_hash, strcmp)) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -49,8 +49,11 @@
|
||||
* backend
|
||||
* 07/05/2014 Mark Riddoch Addition of callback mechanism
|
||||
* 20/06/2014 Mark Riddoch Addition of dcb_clone
|
||||
* 29/05/2015 Markus Makela Addition of dcb_write_SSL
|
||||
* 29/05/2015 Markus Makela Addition of dcb_write_SSL
|
||||
* 11/06/2015 Martin Brampton Persistent connnections and tidy up
|
||||
* 07/07/2015 Martin Brampton Merged add to zombieslist into dcb_close,
|
||||
* fixes for various error situations,
|
||||
* remove dcb_set_state etc, simplifications.
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -59,6 +62,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <dcb.h>
|
||||
#include <spinlock.h>
|
||||
#include <server.h>
|
||||
@ -86,10 +90,6 @@ static SPINLOCK dcbspin = SPINLOCK_INIT;
|
||||
static SPINLOCK zombiespin = SPINLOCK_INIT;
|
||||
|
||||
static void dcb_final_free(DCB *dcb);
|
||||
static bool dcb_set_state_nolock(
|
||||
DCB *dcb,
|
||||
const dcb_state_t new_state,
|
||||
dcb_state_t *old_state);
|
||||
static void dcb_call_callback(DCB *dcb, DCB_REASON reason);
|
||||
static DCB * dcb_get_next (DCB *dcb);
|
||||
static int dcb_null_write(DCB *dcb, GWBUF *buf);
|
||||
@ -237,52 +237,6 @@ dcb_free(DCB *dcb)
|
||||
dcb_final_free(dcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the DCB to the end of zombies list.
|
||||
*
|
||||
* Adding to list occurs once per DCB. This is ensured by changing the
|
||||
* state of DCB to DCB_STATE_ZOMBIE after addition. Prior insertion, DCB state
|
||||
* is checked and operation proceeds only if state differs from DCB_STATE_ZOMBIE.
|
||||
* @param dcb The DCB to add to the zombie list
|
||||
* @return none
|
||||
*/
|
||||
void
|
||||
dcb_add_to_zombieslist(DCB *dcb)
|
||||
{
|
||||
bool succp = false;
|
||||
dcb_state_t prev_state = DCB_STATE_UNDEFINED;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
|
||||
/*<
|
||||
* Protect zombies list access.
|
||||
*/
|
||||
spinlock_acquire(&zombiespin);
|
||||
/*<
|
||||
* If dcb is already added to zombies list, return.
|
||||
*/
|
||||
if (dcb->state != DCB_STATE_NOPOLLING) {
|
||||
ss_dassert(dcb->state != DCB_STATE_POLLING &&
|
||||
dcb->state != DCB_STATE_LISTENING);
|
||||
spinlock_release(&zombiespin);
|
||||
return;
|
||||
}
|
||||
|
||||
/*<
|
||||
* Add closing dcb to the top of the list.
|
||||
*/
|
||||
dcb->memdata.next = zombies;
|
||||
zombies = dcb;
|
||||
/*<
|
||||
* Set state which indicates that it has been added to zombies
|
||||
* list.
|
||||
*/
|
||||
succp = dcb_set_state(dcb, DCB_STATE_ZOMBIE, &prev_state);
|
||||
ss_info_dassert(succp, "Failed to set DCB_STATE_ZOMBIE");
|
||||
|
||||
spinlock_release(&zombiespin);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clone a DCB for internal use, mostly used for specialist filters
|
||||
* to create dummy clients based on real clients.
|
||||
@ -599,8 +553,7 @@ bool succp = false;
|
||||
&tls_log_info.li_sesid,
|
||||
&tls_log_info.li_enabled_logs)));
|
||||
|
||||
succp = dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL);
|
||||
ss_dassert(succp);
|
||||
dcb->state = DCB_STATE_DISCONNECTED;
|
||||
nextdcb = dcb->memdata.next;
|
||||
dcb_final_free(dcb);
|
||||
dcb = nextdcb;
|
||||
@ -615,7 +568,7 @@ bool succp = false;
|
||||
* Connect to a server
|
||||
*
|
||||
* This routine will create a server connection
|
||||
* If succesful the new dcb will be put in
|
||||
* If successful the new dcb will be put in
|
||||
* epoll set by dcb->func.connect
|
||||
*
|
||||
* @param server The server to connect to
|
||||
@ -626,11 +579,11 @@ bool succp = false;
|
||||
DCB *
|
||||
dcb_connect(SERVER *server, SESSION *session, const char *protocol)
|
||||
{
|
||||
DCB *dcb;
|
||||
GWPROTOCOL *funcs;
|
||||
int fd;
|
||||
int rc;
|
||||
char *user;
|
||||
DCB *dcb;
|
||||
GWPROTOCOL *funcs;
|
||||
int fd;
|
||||
int rc;
|
||||
char *user;
|
||||
|
||||
user = session_getUser(session);
|
||||
if (user && strlen(user))
|
||||
@ -677,7 +630,7 @@ char *user;
|
||||
if ((funcs = (GWPROTOCOL *)load_module(protocol,
|
||||
MODULE_PROTOCOL)) == NULL)
|
||||
{
|
||||
dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL);
|
||||
dcb->state = DCB_STATE_DISCONNECTED;
|
||||
dcb_final_free(dcb);
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
@ -716,7 +669,7 @@ char *user;
|
||||
dcb,
|
||||
session->client,
|
||||
session->client->fd)));
|
||||
dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL);
|
||||
dcb->state = DCB_STATE_DISCONNECTED;
|
||||
dcb_final_free(dcb);
|
||||
return NULL;
|
||||
} else {
|
||||
@ -758,10 +711,10 @@ char *user;
|
||||
*/
|
||||
rc = poll_add_dcb(dcb);
|
||||
|
||||
if (rc == DCBFD_CLOSED) {
|
||||
dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL);
|
||||
dcb_final_free(dcb);
|
||||
return NULL;
|
||||
if (rc) {
|
||||
dcb->state = DCB_STATE_DISCONNECTED;
|
||||
dcb_final_free(dcb);
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* The dcb will be addded into poll set by dcb->func.connect
|
||||
@ -973,10 +926,10 @@ int dcb_read_n(
|
||||
goto return_n;
|
||||
}
|
||||
|
||||
if (b == 0 && nread == 0)
|
||||
if (b == 0)
|
||||
{
|
||||
/** Handle closed client socket */
|
||||
if (dcb_isclient(dcb))
|
||||
if (nread == 0 && dcb_isclient(dcb))
|
||||
{
|
||||
char c;
|
||||
int l_errno = 0;
|
||||
@ -998,11 +951,6 @@ int dcb_read_n(
|
||||
n = 0;
|
||||
goto return_n;
|
||||
}
|
||||
else if (b == 0)
|
||||
{
|
||||
n = 0;
|
||||
goto return_n;
|
||||
}
|
||||
|
||||
dcb->last_read = hkheartbeat;
|
||||
|
||||
@ -1242,6 +1190,10 @@ int dcb_read_SSL(
|
||||
}
|
||||
|
||||
gwbuf_rtrim(buffer,bufsize - n);
|
||||
if(buffer == NULL)
|
||||
{
|
||||
goto return_n;
|
||||
}
|
||||
#ifdef SS_DEBUG
|
||||
skygw_log_write(LD,"%lu SSL: Truncated buffer from %d to %d bytes. "
|
||||
"Read %d bytes, %d bytes waiting.\n",pthread_self(),
|
||||
@ -1268,12 +1220,9 @@ int dcb_read_SSL(
|
||||
|
||||
/*< Append read data to the gwbuf */
|
||||
*head = gwbuf_append(*head, buffer);
|
||||
rc = ioctl(dcb->fd, FIONREAD, &b);
|
||||
pending = SSL_pending(dcb->ssl);
|
||||
|
||||
} /*< while (true) */
|
||||
return_n:
|
||||
return n;
|
||||
return nread;
|
||||
}
|
||||
/**
|
||||
* General purpose routine to write to a DCB
|
||||
@ -1628,95 +1577,116 @@ dcb_write_SSL(DCB *dcb, GWBUF *queue)
|
||||
}
|
||||
#endif /* FAKE_CODE */
|
||||
qlen = GWBUF_LENGTH(queue);
|
||||
|
||||
w = gw_write_SSL(dcb->ssl, GWBUF_DATA(queue), qlen);
|
||||
dcb->stats.n_writes++;
|
||||
|
||||
if (w < 0)
|
||||
do
|
||||
{
|
||||
int ssl_errno = SSL_get_error(dcb->ssl,w);
|
||||
w = gw_write_SSL(dcb->ssl, GWBUF_DATA(queue), qlen);
|
||||
dcb->stats.n_writes++;
|
||||
|
||||
if (LOG_IS_ENABLED(LOGFILE_DEBUG))
|
||||
if (w <= 0)
|
||||
{
|
||||
switch(ssl_errno)
|
||||
int ssl_errno = SSL_get_error(dcb->ssl,w);
|
||||
|
||||
if (LOG_IS_ENABLED(LOGFILE_DEBUG))
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Write to dcb "
|
||||
"%p in state %s fd %d failed "
|
||||
"due error SSL_ERROR_WANT_READ",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Write to dcb "
|
||||
"%p in state %s fd %d failed "
|
||||
"due error SSL_ERROR_WANT_WRITE",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
break;
|
||||
default:
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Write to dcb "
|
||||
"%p in state %s fd %d failed "
|
||||
"due error %d",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,ssl_errno)));
|
||||
if(ssl_errno == SSL_ERROR_SSL ||
|
||||
ssl_errno == SSL_ERROR_SYSCALL)
|
||||
switch(ssl_errno)
|
||||
{
|
||||
while((ssl_errno = ERR_get_error()) != 0)
|
||||
case SSL_ERROR_WANT_READ:
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Write to dcb "
|
||||
"%p in state %s fd %d failed "
|
||||
"due error SSL_ERROR_WANT_READ",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Write to dcb "
|
||||
"%p in state %s fd %d failed "
|
||||
"due error SSL_ERROR_WANT_WRITE",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
break;
|
||||
default:
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Write to dcb "
|
||||
"%p in state %s fd %d failed "
|
||||
"due error %d",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,ssl_errno)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG_IS_ENABLED(LOGFILE_ERROR) && ssl_errno != SSL_ERROR_WANT_WRITE)
|
||||
{
|
||||
if (ssl_errno == -1)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Write to dcb %p in "
|
||||
"state %s fd %d failed due to "
|
||||
"SSL error %d",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
ssl_errno)));
|
||||
if(ssl_errno == SSL_ERROR_SSL || ssl_errno == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
char errbuf[140];
|
||||
ERR_error_string(ssl_errno,errbuf);
|
||||
skygw_log_write(LE,"%s",errbuf);
|
||||
if(ssl_errno == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
skygw_log_write(LE,"%d:%s",errno,strerror(errno));
|
||||
}
|
||||
do
|
||||
{
|
||||
char errbuf[140];
|
||||
ERR_error_string(ssl_errno,errbuf);
|
||||
skygw_log_write(LE,"%d:%s",ssl_errno,errbuf);
|
||||
}while((ssl_errno = ERR_get_error()) != 0);
|
||||
}
|
||||
}
|
||||
else if(w == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
char errbuf[140];
|
||||
ERR_error_string(ssl_errno,errbuf);
|
||||
skygw_log_write(LE,"%d:%s",ssl_errno,errbuf);
|
||||
}while((ssl_errno = ERR_get_error()) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(ssl_errno != SSL_ERROR_WANT_WRITE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG_IS_ENABLED(LOGFILE_ERROR))
|
||||
{
|
||||
if (ssl_errno != 0)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Write to dcb %p in "
|
||||
"state %s fd %d failed due "
|
||||
"SSL error %d",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
ssl_errno)));
|
||||
}
|
||||
}
|
||||
}while(w <= 0);
|
||||
|
||||
if(w <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Pull the number of bytes we have written from
|
||||
* queue with have.
|
||||
*/
|
||||
queue = gwbuf_consume(queue, w);
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
else
|
||||
{
|
||||
/** Remove written bytes from the queue */
|
||||
queue = gwbuf_consume(queue, w);
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Wrote %d Bytes to dcb %p in "
|
||||
"state %s fd %d",
|
||||
"state %s fd %d",
|
||||
pthread_self(),
|
||||
w,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
}
|
||||
} /*< while (queue != NULL) */
|
||||
/*<
|
||||
* What wasn't successfully written is stored to write queue
|
||||
@ -1734,38 +1704,6 @@ dcb_write_SSL(DCB *dcb, GWBUF *queue)
|
||||
}
|
||||
} /* if (dcb->writeq) */
|
||||
|
||||
if (saved_errno != 0 &&
|
||||
queue != NULL &&
|
||||
saved_errno != EAGAIN &&
|
||||
saved_errno != EWOULDBLOCK)
|
||||
{
|
||||
bool dolog = true;
|
||||
|
||||
/**
|
||||
* Do not log if writing COM_QUIT to backend failed.
|
||||
*/
|
||||
if (GWBUF_IS_TYPE_MYSQL(queue))
|
||||
{
|
||||
uint8_t* data = GWBUF_DATA(queue);
|
||||
|
||||
if (data[4] == 0x01)
|
||||
{
|
||||
dolog = false;
|
||||
}
|
||||
}
|
||||
if (dolog)
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_write] Writing to %s socket failed due %d, %s.",
|
||||
pthread_self(),
|
||||
dcb_isclient(dcb) ? "client" : "backend server",
|
||||
saved_errno,
|
||||
strerror(saved_errno))));
|
||||
}
|
||||
spinlock_release(&dcb->writeqlock);
|
||||
return 0;
|
||||
}
|
||||
spinlock_release(&dcb->writeqlock);
|
||||
|
||||
if (dcb->high_water && dcb->writeqlen > dcb->high_water && below_water)
|
||||
@ -1901,28 +1839,47 @@ dcb_drain_writeq_SSL(DCB *dcb)
|
||||
while (dcb->writeq != NULL)
|
||||
{
|
||||
len = GWBUF_LENGTH(dcb->writeq);
|
||||
w = gw_write_SSL(dcb->ssl, GWBUF_DATA(dcb->writeq), len);
|
||||
w = gw_write_SSL(dcb->ssl, GWBUF_DATA(dcb->writeq), len);
|
||||
|
||||
if (w < 0)
|
||||
{
|
||||
int ssl_errno = ERR_get_error();
|
||||
int ssl_errno = SSL_get_error(dcb->ssl,w);
|
||||
|
||||
if(ssl_errno == SSL_ERROR_WANT_WRITE ||
|
||||
ssl_errno == SSL_ERROR_WANT_ACCEPT ||
|
||||
ssl_errno == SSL_ERROR_WANT_READ)
|
||||
if(ssl_errno == SSL_ERROR_WANT_WRITE || ssl_errno == SSL_ERROR_WANT_READ)
|
||||
{
|
||||
break;
|
||||
}
|
||||
skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Error : Write to dcb failed due to "
|
||||
"SSL error %d:",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
ssl_errno);
|
||||
switch(ssl_errno)
|
||||
{
|
||||
case SSL_ERROR_SSL:
|
||||
case SSL_ERROR_SYSCALL:
|
||||
while((ssl_errno = ERR_get_error()) != 0)
|
||||
{
|
||||
char errbuf[140];
|
||||
ERR_error_string(ssl_errno,errbuf);
|
||||
skygw_log_write(LE,"%s",errbuf);
|
||||
}
|
||||
if(errno != 0)
|
||||
skygw_log_write(LE,"%d:%s",errno,strerror(errno));
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
skygw_log_write(LE,"Socket is closed.");
|
||||
break;
|
||||
|
||||
skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Write to dcb %p "
|
||||
"in state %s fd %d failed: %s",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
ERR_error_string(ssl_errno,NULL));
|
||||
default:
|
||||
skygw_log_write(LE,"Unexpected error.");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* Pull the number of bytes we have written from
|
||||
@ -1962,62 +1919,100 @@ dcb_drain_writeq_SSL(DCB *dcb)
|
||||
void
|
||||
dcb_close(DCB *dcb)
|
||||
{
|
||||
CHK_DCB(dcb);
|
||||
CHK_DCB(dcb);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG,
|
||||
"%lu [dcb_close]",
|
||||
pthread_self())));
|
||||
|
||||
/**
|
||||
* dcb_close may be called for freshly created dcb, in which case
|
||||
* it only needs to be freed.
|
||||
*/
|
||||
if (dcb->state == DCB_STATE_ALLOC)
|
||||
LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG,
|
||||
"%lu [dcb_close] DCB %p in state %s",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
dcb ? STRDCBSTATE(dcb->state) : "Invalid DCB")));
|
||||
|
||||
if (DCB_STATE_ZOMBIE == dcb->state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DCB_STATE_UNDEFINED == dcb->state
|
||||
|| DCB_STATE_DISCONNECTED == dcb->state)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [dcb_close] Error : Removing DCB %p but was in state %s "
|
||||
"which is not legal for a call to dcb_close. ",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
raise(SIGABRT);
|
||||
}
|
||||
|
||||
/**
|
||||
* dcb_close may be called for freshly created dcb, in which case
|
||||
* it only needs to be freed.
|
||||
*/
|
||||
if (dcb->state == DCB_STATE_ALLOC && dcb->fd != DCBFD_CLOSED)
|
||||
{
|
||||
dcb_final_free(dcb);
|
||||
return;
|
||||
}
|
||||
|
||||
/*<
|
||||
* Stop dcb's listening and modify state accordingly.
|
||||
*/
|
||||
if (dcb->state == DCB_STATE_POLLING || dcb->state == DCB_STATE_LISTENING)
|
||||
{
|
||||
if (dcb->state == DCB_STATE_LISTENING)
|
||||
{
|
||||
dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL);
|
||||
dcb_final_free(dcb);
|
||||
return;
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [dcb_close] Error : Removing DCB %p but was in state %s "
|
||||
"which is not expected for a call to dcb_close, although it"
|
||||
"should be processed correctly. ",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
|
||||
ss_dassert(dcb->state == DCB_STATE_POLLING ||
|
||||
dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE);
|
||||
|
||||
/*<
|
||||
* Stop dcb's listening and modify state accordingly.
|
||||
*/
|
||||
if (dcb->state == DCB_STATE_POLLING)
|
||||
if ((dcb->state == DCB_STATE_POLLING && !dcb_maybe_add_persistent(dcb))
|
||||
|| (dcb->state == DCB_STATE_LISTENING))
|
||||
{
|
||||
if (!dcb_maybe_add_persistent(dcb))
|
||||
poll_remove_dcb(dcb);
|
||||
/*
|
||||
* Return will always be 0 or function will have crashed, so we
|
||||
* threw away return value.
|
||||
*/
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_close] Removed dcb %p in state %s from "
|
||||
"poll set.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
/**
|
||||
* close protocol and router session
|
||||
*/
|
||||
if (dcb->func.close != NULL)
|
||||
{
|
||||
if (poll_remove_dcb(dcb))
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Removing DCB fd == %d in state %s from "
|
||||
"poll set failed.",
|
||||
dcb->fd,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_close] Removed dcb %p in state %s from "
|
||||
"poll set.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
|
||||
dcb_close_finish(dcb);
|
||||
ss_dassert(dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE);
|
||||
}
|
||||
ss_dassert(dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE ||
|
||||
dcb->state == DCB_STATE_POLLING);
|
||||
dcb->func.close(dcb);
|
||||
}
|
||||
/** Call possible callback for this DCB in case of close */
|
||||
dcb_call_callback(dcb, DCB_REASON_CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_acquire(&zombiespin);
|
||||
if (dcb->state == DCB_STATE_NOPOLLING || dcb->state == DCB_STATE_ALLOC)
|
||||
{
|
||||
/*<
|
||||
* Add closing dcb to the top of the list.
|
||||
*/
|
||||
dcb->memdata.next = zombies;
|
||||
zombies = dcb;
|
||||
/*<
|
||||
* Set state which indicates that it has been added to zombies
|
||||
* list.
|
||||
*/
|
||||
dcb->state = DCB_STATE_ZOMBIE;
|
||||
}
|
||||
spinlock_release(&zombiespin);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2097,7 +2092,7 @@ dcb_close_finish(DCB *dcb)
|
||||
/** Call possible callback for this DCB in case of close */
|
||||
dcb_call_callback(dcb, DCB_REASON_CLOSE);
|
||||
/** Must be DCB_STATE_NOPOLLING when this function is called */
|
||||
dcb_add_to_zombieslist(dcb);
|
||||
dcb_close(dcb);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2291,7 +2286,7 @@ DCB *dcb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diagnotic routine to print client DCB data in a tabular form.
|
||||
* Diagnostic routine to print client DCB data in a tabular form.
|
||||
*
|
||||
* @param pdcb DCB to print results to
|
||||
*/
|
||||
@ -2417,7 +2412,8 @@ dprintDCB(DCB *pdcb, DCB *dcb)
|
||||
*
|
||||
*/
|
||||
const char *
|
||||
gw_dcb_state2string (int state) {
|
||||
gw_dcb_state2string (int state)
|
||||
{
|
||||
switch(state) {
|
||||
case DCB_STATE_ALLOC:
|
||||
return "DCB Allocated";
|
||||
@ -2515,155 +2511,6 @@ void dcb_hashtable_stats(
|
||||
dcb_printf(dcb, "\tLongest chain length: %d\n", longest);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
dcb_set_state(
|
||||
DCB *dcb,
|
||||
const dcb_state_t new_state,
|
||||
dcb_state_t *old_state_ptr)
|
||||
{
|
||||
bool succp;
|
||||
dcb_state_t old_state_buffer;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
|
||||
spinlock_acquire(&dcb->dcb_initlock);
|
||||
succp = dcb_set_state_nolock(dcb, new_state, &old_state_buffer);
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
|
||||
if (old_state_ptr != NULL)
|
||||
{
|
||||
*old_state_ptr = old_state_buffer;
|
||||
}
|
||||
return succp;
|
||||
}
|
||||
|
||||
static bool
|
||||
dcb_set_state_nolock(
|
||||
DCB *dcb,
|
||||
const dcb_state_t new_state,
|
||||
dcb_state_t *old_state_ptr)
|
||||
{
|
||||
bool succp = false;
|
||||
bool old_state_supplied = true;
|
||||
dcb_state_t state_buffer;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
|
||||
if (NULL == old_state_ptr)
|
||||
{
|
||||
old_state_supplied = false;
|
||||
old_state_ptr = &state_buffer;
|
||||
}
|
||||
*old_state_ptr = dcb->state;
|
||||
|
||||
switch (*old_state_ptr) {
|
||||
case DCB_STATE_UNDEFINED:
|
||||
dcb->state = new_state;
|
||||
succp = true;
|
||||
break;
|
||||
|
||||
case DCB_STATE_ALLOC:
|
||||
switch (new_state) {
|
||||
/** fall through, for client requests */
|
||||
case DCB_STATE_POLLING:
|
||||
/** fall through, for connect listeners */
|
||||
case DCB_STATE_LISTENING:
|
||||
/** for failed connections */
|
||||
case DCB_STATE_DISCONNECTED:
|
||||
dcb->state = new_state;
|
||||
succp = true;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
|
||||
case DCB_STATE_POLLING:
|
||||
switch(new_state) {
|
||||
case DCB_STATE_NOPOLLING:
|
||||
dcb->state = new_state;
|
||||
succp = true;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
|
||||
case DCB_STATE_LISTENING:
|
||||
switch(new_state) {
|
||||
case DCB_STATE_NOPOLLING:
|
||||
dcb->state = new_state;
|
||||
succp = true;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
|
||||
case DCB_STATE_NOPOLLING:
|
||||
switch (new_state) {
|
||||
case DCB_STATE_ZOMBIE: /*< fall through */
|
||||
dcb->state = new_state;
|
||||
case DCB_STATE_POLLING: /*< ok to try but state can't change */
|
||||
succp = true;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
|
||||
case DCB_STATE_ZOMBIE:
|
||||
switch (new_state) {
|
||||
case DCB_STATE_DISCONNECTED: /*< fall through */
|
||||
dcb->state = new_state;
|
||||
case DCB_STATE_POLLING: /*< ok to try but state can't change */
|
||||
succp = true;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
|
||||
case DCB_STATE_DISCONNECTED:
|
||||
switch (new_state) {
|
||||
case DCB_STATE_FREED:
|
||||
dcb->state = new_state;
|
||||
succp = true;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
|
||||
case DCB_STATE_FREED:
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Unknown dcb state %s for "
|
||||
"dcb %p",
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb)));
|
||||
ss_dassert(false);
|
||||
break;
|
||||
} /*< switch (dcb->state) */
|
||||
|
||||
if (succp) {
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_set_state_nolock] dcb %p fd %d %s -> %s",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
dcb->fd,
|
||||
STRDCBSTATE(*old_state_ptr),
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_set_state_nolock] Failed "
|
||||
"to change state of DCB %p. "
|
||||
"Old state %s > new state %s.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
(old_state_ptr == NULL ? "NULL" : STRDCBSTATE(*old_state_ptr)),
|
||||
STRDCBSTATE(new_state))));
|
||||
ss_dassert(old_state_supplied);
|
||||
}
|
||||
return succp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to a socket through an SSL structure. The SSL structure is linked to a DCB's socket
|
||||
* and all communication is encrypted and done via the SSL structure.
|
||||
@ -3236,7 +3083,7 @@ int dcb_accept_SSL(DCB* dcb)
|
||||
do
|
||||
{
|
||||
ssl_rval = SSL_accept(dcb->ssl);
|
||||
errnum = SSL_get_error(dcb->ssl,ssl_rval);
|
||||
|
||||
LOGIF(LD,(skygw_log_write_flush(LD,"[dcb_accept_SSL] SSL_accept %d, error %d",
|
||||
ssl_rval,errnum)));
|
||||
switch(ssl_rval)
|
||||
|
||||
@ -208,6 +208,15 @@ static int set_user();
|
||||
|
||||
/** SSL multi-threading functions and structures */
|
||||
|
||||
static SPINLOCK* ssl_locks;
|
||||
|
||||
static void ssl_locking_function(int mode,int n,const char* file, int line)
|
||||
{
|
||||
if(mode & CRYPTO_LOCK)
|
||||
spinlock_acquire(&ssl_locks[n]);
|
||||
else
|
||||
spinlock_release(&ssl_locks[n]);
|
||||
}
|
||||
/**
|
||||
* OpenSSL requires this struct to be defined in order to use dynamic locks
|
||||
*/
|
||||
@ -263,6 +272,17 @@ static void ssl_free_dynlock(struct CRYPTO_dynlock_value * n,const char* file, i
|
||||
free(n);
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_1_0
|
||||
/**
|
||||
* The thread ID callback function for OpenSSL dynamic locks.
|
||||
* @param id Id to modify
|
||||
*/
|
||||
static void maxscale_ssl_id(CRYPTO_THREADID* id)
|
||||
{
|
||||
CRYPTO_THREADID_set_numeric(id,pthread_self());
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Handler for SIGHUP signal. Reload the configuration for the
|
||||
* gateway.
|
||||
@ -1456,10 +1476,6 @@ int main(int argc, char **argv)
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
OPENSSL_add_all_algorithms_noconf();
|
||||
CRYPTO_set_dynlock_create_callback(ssl_create_dynlock);
|
||||
CRYPTO_set_dynlock_destroy_callback(ssl_free_dynlock);
|
||||
CRYPTO_set_dynlock_lock_callback(ssl_lock_dynlock);
|
||||
CRYPTO_set_id_callback(pthread_self);
|
||||
|
||||
/* register exit function for embedded MySQL library */
|
||||
l = atexit(libmysqld_done);
|
||||
@ -1515,17 +1531,13 @@ int main(int argc, char **argv)
|
||||
/** Use default log directory /var/log/maxscale/ */
|
||||
if(logdir == NULL)
|
||||
{
|
||||
|
||||
if(access(default_logdir,F_OK) != 0)
|
||||
{
|
||||
if(mkdir(logdir,0555) != 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Error: Cannot create log directory: %s\n",
|
||||
default_logdir);
|
||||
goto return_main;
|
||||
}
|
||||
}
|
||||
if(mkdir(default_logdir,0777) != 0 && errno != EEXIST)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Error: Cannot create log directory: %s\n",
|
||||
default_logdir);
|
||||
goto return_main;
|
||||
}
|
||||
logdir = strdup(default_logdir);
|
||||
}
|
||||
|
||||
@ -1582,7 +1594,7 @@ int main(int argc, char **argv)
|
||||
/**
|
||||
* Set a data directory for the mysqld library, we use
|
||||
* a unique directory name to avoid clauses if multiple
|
||||
* instances of the gateway are beign run on the same
|
||||
* instances of the gateway are being run on the same
|
||||
* machine.
|
||||
*/
|
||||
|
||||
@ -1793,6 +1805,26 @@ int main(int argc, char **argv)
|
||||
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
|
||||
"MaxScale started with %d server threads.",
|
||||
config_threadcount())));
|
||||
int numlocks = CRYPTO_num_locks();
|
||||
if((ssl_locks = malloc(sizeof(SPINLOCK)*(numlocks + 1))) == NULL)
|
||||
{
|
||||
char* logerr = "Memory allocation failed";
|
||||
print_log_n_stderr(true, true, logerr, logerr, eno);
|
||||
rc = MAXSCALE_INTERNALERROR;
|
||||
goto return_main;
|
||||
}
|
||||
|
||||
for(i = 0;i<numlocks + 1;i++)
|
||||
spinlock_init(&ssl_locks[i]);
|
||||
CRYPTO_set_locking_callback(ssl_locking_function);
|
||||
CRYPTO_set_dynlock_create_callback(ssl_create_dynlock);
|
||||
CRYPTO_set_dynlock_destroy_callback(ssl_free_dynlock);
|
||||
CRYPTO_set_dynlock_lock_callback(ssl_lock_dynlock);
|
||||
#ifdef OPENSSL_1_0
|
||||
CRYPTO_THREADID_set_callback(maxscale_ssl_id);
|
||||
#else
|
||||
CRYPTO_set_id_callback(pthread_self);
|
||||
#endif
|
||||
|
||||
MaxScaleStarted = time(0);
|
||||
/*<
|
||||
|
||||
@ -192,6 +192,7 @@ monitorAddServer(MONITOR *mon, SERVER *server)
|
||||
db->con = NULL;
|
||||
db->next = NULL;
|
||||
db->mon_err_count = 0;
|
||||
db->log_version_err = true;
|
||||
/** Server status is uninitialized */
|
||||
db->mon_prev_status = -1;
|
||||
/* pending status is updated by get_replication_tree */
|
||||
|
||||
@ -15,10 +15,12 @@
|
||||
*
|
||||
* Copyright MariaDB Corporation Ab 2013-2014
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
@ -71,6 +73,7 @@ int max_poll_sleep;
|
||||
* in the loop after the epoll_wait. This allows for better
|
||||
* thread utilisaiton and fairer scheduling of the event
|
||||
* processing.
|
||||
* 07/07/15 Martin Brampton Simplified add and remove DCB, improve error handling.
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -186,6 +189,11 @@ static struct {
|
||||
*/
|
||||
static void poll_loadav(void *);
|
||||
|
||||
/**
|
||||
* Function to analyse error return from epoll_ctl
|
||||
*/
|
||||
static int poll_resolve_error(DCB *, int, bool);
|
||||
|
||||
/**
|
||||
* Initialise the polling system we are using for the gateway.
|
||||
*
|
||||
@ -247,7 +255,7 @@ int
|
||||
poll_add_dcb(DCB *dcb)
|
||||
{
|
||||
int rc = -1;
|
||||
dcb_state_t old_state = DCB_STATE_UNDEFINED;
|
||||
dcb_state_t old_state = dcb->state;
|
||||
dcb_state_t new_state;
|
||||
struct epoll_event ev;
|
||||
|
||||
@ -263,58 +271,67 @@ poll_add_dcb(DCB *dcb)
|
||||
/*<
|
||||
* Choose new state according to the role of dcb.
|
||||
*/
|
||||
spinlock_acquire(&dcb->dcb_initlock);
|
||||
if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER) {
|
||||
new_state = DCB_STATE_POLLING;
|
||||
} else {
|
||||
ss_dassert(dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER);
|
||||
new_state = DCB_STATE_LISTENING;
|
||||
}
|
||||
/*<
|
||||
* If dcb is in unexpected state, state change fails indicating that dcb
|
||||
* is not polling anymore.
|
||||
/*
|
||||
* Check DCB current state seems sensible
|
||||
*/
|
||||
if (dcb_set_state(dcb, new_state, &old_state)) {
|
||||
rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);
|
||||
|
||||
if (rc != 0) {
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Adding dcb %p in state %s "
|
||||
"to poll set failed. epoll_ctl failed due "
|
||||
"%d, %s.",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
eno,
|
||||
strerror(eno))));
|
||||
} else {
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [poll_add_dcb] Added dcb %p in state %s to "
|
||||
"poll set.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
ss_info_dassert(rc == 0, "Unable to add poll"); /*< trap in debug */
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Unable to set new state for dcb %p "
|
||||
"in state %s. Adding to poll set failed.",
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
if (DCB_STATE_DISCONNECTED == dcb->state
|
||||
|| DCB_STATE_ZOMBIE == dcb->state
|
||||
|| DCB_STATE_UNDEFINED == dcb->state)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [poll_add_dcb] Error : existing state of dcb %p "
|
||||
"is %s, but this should be impossible, crashing.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
raise(SIGABRT);
|
||||
}
|
||||
|
||||
if (DCB_STATE_POLLING == dcb->state
|
||||
|| DCB_STATE_LISTENING == dcb->state)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [poll_add_dcb] Error : existing state of dcb %p "
|
||||
"is %s, but this is probably an error, not crashing.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
dcb->state = new_state;
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
/*
|
||||
* The only possible failure that will not cause a crash is
|
||||
* running out of system resources.
|
||||
*/
|
||||
rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);
|
||||
if (rc)
|
||||
{
|
||||
rc = poll_resolve_error(dcb, errno, true);
|
||||
}
|
||||
if (0 == rc)
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [poll_add_dcb] Added dcb %p in state %s to poll set.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
else dcb->state = old_state;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a descriptor from the set of descriptors within the
|
||||
* polling environment.
|
||||
* The state change command may fail because concurrent threads may call
|
||||
* dcb_set_state simultaneously and the conflict is prevented in dcb_set_state.
|
||||
*
|
||||
* @param dcb The descriptor to remove
|
||||
* @return -1 on error or 0 on success
|
||||
@ -322,61 +339,121 @@ poll_add_dcb(DCB *dcb)
|
||||
int
|
||||
poll_remove_dcb(DCB *dcb)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int rc = -1;
|
||||
dcb_state_t old_state = DCB_STATE_UNDEFINED;
|
||||
dcb_state_t new_state = DCB_STATE_NOPOLLING;
|
||||
|
||||
struct epoll_event ev;
|
||||
CHK_DCB(dcb);
|
||||
|
||||
spinlock_acquire(&dcb->dcb_initlock);
|
||||
/*< It is possible that dcb has already been removed from the set */
|
||||
if (dcb->state != DCB_STATE_POLLING)
|
||||
{
|
||||
if (dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE)
|
||||
{
|
||||
rc = 0;
|
||||
}
|
||||
goto return_rc;
|
||||
if (dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE)
|
||||
{
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
return 0;
|
||||
}
|
||||
if (DCB_STATE_POLLING != dcb->state
|
||||
&& DCB_STATE_LISTENING != dcb->state)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [poll_remove_dcb] Error : existing state of dcb %p "
|
||||
"is %s, but this is probably an error, not crashing.",
|
||||
pthread_self(),
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
/*<
|
||||
* Set state to NOPOLLING and remove dcb from poll set.
|
||||
*/
|
||||
if (dcb_set_state(dcb, new_state, &old_state))
|
||||
{
|
||||
/**
|
||||
* Only positive fds can be removed from epoll set.
|
||||
*/
|
||||
if (dcb->fd > 0)
|
||||
{
|
||||
rc = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dcb->fd, &ev);
|
||||
|
||||
if (rc != 0) {
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : epoll_ctl failed due %d, %s.",
|
||||
eno,
|
||||
strerror(eno))));
|
||||
}
|
||||
ss_dassert(rc == 0); /*< trap in debug */
|
||||
}
|
||||
}
|
||||
/*<
|
||||
* This call was redundant, but the end result is correct.
|
||||
dcb->state = DCB_STATE_NOPOLLING;
|
||||
/**
|
||||
* Only positive fds can be removed from epoll set.
|
||||
* But this test was removed by Martin as it is hard to
|
||||
* see that there should ever be a situation where
|
||||
* fd isn't positive and the DCB is also in the poll list.
|
||||
*/
|
||||
/* if (dcb->fd > 0) { */
|
||||
spinlock_release(&dcb->dcb_initlock);
|
||||
rc = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dcb->fd, &ev);
|
||||
/**
|
||||
* The poll_resolve_error function will always
|
||||
* return 0 or crash. So if it returns non-zero result,
|
||||
* things have gone wrong and we crash.
|
||||
*/
|
||||
else if (old_state == new_state)
|
||||
{
|
||||
rc = 0;
|
||||
goto return_rc;
|
||||
}
|
||||
|
||||
if (rc) rc = poll_resolve_error(dcb, errno, false);
|
||||
if (rc) raise(SIGABRT);
|
||||
/*< Set bit for each maxscale thread */
|
||||
bitmask_copy(&dcb->memdata.bitmask, poll_bitmask());
|
||||
rc = 0;
|
||||
return_rc:
|
||||
bitmask_copy(&dcb->memdata.bitmask, poll_bitmask());
|
||||
return rc;
|
||||
/* } */
|
||||
}
|
||||
|
||||
/**
|
||||
* Check error returns from epoll_ctl. Most result in a crash since they
|
||||
* are "impossible". Adding when already present is assumed non-fatal.
|
||||
* Likewise, removing when not present is assumed non-fatal.
|
||||
* It is assumed that callers to poll routines can handle the failure
|
||||
* that results from hitting system limit, although an error is written
|
||||
* here to record the problem.
|
||||
*
|
||||
* @param errornum The errno set by epoll_ctl
|
||||
* @param adding True for adding to poll list, false for removing
|
||||
* @return -1 on error or 0 for possibly revised return code
|
||||
*/
|
||||
static int
|
||||
poll_resolve_error(DCB *dcb, int errornum, bool adding)
|
||||
{
|
||||
if (adding)
|
||||
{
|
||||
if (EEXIST == errornum)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [poll_resolve_error] Error : epoll_ctl could not add, "
|
||||
"already exists for DCB %p.",
|
||||
pthread_self(),
|
||||
dcb)));
|
||||
// Assume another thread added and no serious harm done
|
||||
return 0;
|
||||
}
|
||||
if (ENOSPC == errornum)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [poll_resolve_error] The limit imposed by "
|
||||
"/proc/sys/fs/epoll/max_user_watches was "
|
||||
"encountered while trying to register (EPOLL_CTL_ADD) a new "
|
||||
"file descriptor on an epoll instance for dcb %p.",
|
||||
pthread_self(),
|
||||
dcb)));
|
||||
/* Failure - assume handled by callers */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Must be removing */
|
||||
if (ENOENT == errornum)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [poll_resolve_error] Error : epoll_ctl could not remove, "
|
||||
"not found, for dcb %p.",
|
||||
pthread_self(),
|
||||
dcb)));
|
||||
// Assume another thread removed and no serious harm done
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Common checks for add or remove - crash MaxScale */
|
||||
if (EBADF == errornum) raise(SIGABRT);
|
||||
if (EINVAL == errornum) raise(SIGABRT);
|
||||
if (ENOMEM == errornum) raise(SIGABRT);
|
||||
if (EPERM == errornum) raise(SIGABRT);
|
||||
/* Undocumented error number */
|
||||
raise(SIGABRT);
|
||||
/* The following statement should never be reached, but avoids compiler warning */
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define BLOCKINGPOLL 0 /*< Set BLOCKING POLL to 1 if using a single thread and to make
|
||||
@ -1604,7 +1681,7 @@ RESULT_ROW *row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a resultset that has the current set of services in it
|
||||
* Return a result set that has the current set of services in it
|
||||
*
|
||||
* @return A Result set
|
||||
*/
|
||||
|
||||
@ -228,6 +228,12 @@ unsigned int randval;
|
||||
MAXKEYS key;
|
||||
char secret_file[PATH_MAX + 10];
|
||||
|
||||
if(strlen(path) > PATH_MAX)
|
||||
{
|
||||
skygw_log_write(LOGFILE_ERROR,"Error: Pathname too long.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sprintf(secret_file,"%s/.secrets",path);
|
||||
|
||||
/* Open for writing | Create | Truncate the file for writing */
|
||||
|
||||
@ -126,7 +126,7 @@ SERVICE *service;
|
||||
"Error : Unable to load %s module \"%s\".\n\t\t\t"
|
||||
" Ensure that lib%s.so exists in one of the "
|
||||
"following directories :\n\t\t\t "
|
||||
"- %s/modules\n%s%s",
|
||||
"- %s\n%s%s",
|
||||
MODULE_ROUTER,
|
||||
router,
|
||||
router,
|
||||
@ -269,7 +269,7 @@ GWPROTOCOL *funcs;
|
||||
/* Save authentication data to file cache */
|
||||
char *ptr, path[PATH_MAX + 1];
|
||||
int mkdir_rval = 0;
|
||||
strcpy(path, get_cachedir());
|
||||
strncpy(path, get_cachedir(),PATH_MAX);
|
||||
strncat(path, "/", 4096);
|
||||
strncat(path, service->name, PATH_MAX);
|
||||
if (access(path, R_OK) == -1)
|
||||
@ -535,11 +535,16 @@ int listeners = 0;
|
||||
port = service->ports;
|
||||
while (port)
|
||||
{
|
||||
poll_remove_dcb(port->listener);
|
||||
port->listener->session->state = SESSION_STATE_LISTENER_STOPPED;
|
||||
listeners++;
|
||||
|
||||
port = port->next;
|
||||
if(port->listener &&
|
||||
port->listener->session->state == SESSION_STATE_LISTENER)
|
||||
{
|
||||
if(poll_remove_dcb(port->listener) == 0)
|
||||
{
|
||||
port->listener->session->state = SESSION_STATE_LISTENER_STOPPED;
|
||||
listeners++;
|
||||
}
|
||||
}
|
||||
port = port->next;
|
||||
}
|
||||
service->state = SERVICE_STATE_STOPPED;
|
||||
|
||||
@ -563,13 +568,18 @@ int listeners = 0;
|
||||
port = service->ports;
|
||||
while (port)
|
||||
{
|
||||
if (poll_add_dcb(port->listener) == 0) {
|
||||
port->listener->session->state = SESSION_STATE_LISTENER;
|
||||
listeners++;
|
||||
}
|
||||
port = port->next;
|
||||
if(port->listener &&
|
||||
port->listener->session->state == SESSION_STATE_LISTENER_STOPPED)
|
||||
{
|
||||
if(poll_add_dcb(port->listener) == 0)
|
||||
{
|
||||
port->listener->session->state = SESSION_STATE_LISTENER;
|
||||
listeners++;
|
||||
}
|
||||
}
|
||||
port = port->next;
|
||||
}
|
||||
|
||||
service->state = SERVICE_STATE_STARTED;
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@ -914,10 +924,12 @@ serviceSetSSLVersion(SERVICE *service, char* version)
|
||||
service->ssl_method_type = SERVICE_SSLV3;
|
||||
else if(strcasecmp(version,"TLSV10") == 0)
|
||||
service->ssl_method_type = SERVICE_TLS10;
|
||||
#ifdef OPENSSL_1_0
|
||||
else if(strcasecmp(version,"TLSV11") == 0)
|
||||
service->ssl_method_type = SERVICE_TLS11;
|
||||
else if(strcasecmp(version,"TLSV12") == 0)
|
||||
service->ssl_method_type = SERVICE_TLS12;
|
||||
#endif
|
||||
else if(strcasecmp(version,"MAX") == 0)
|
||||
service->ssl_method_type = SERVICE_SSL_TLS_MAX;
|
||||
else return -1;
|
||||
@ -1957,13 +1969,14 @@ int serviceInitSSL(SERVICE* service)
|
||||
case SERVICE_TLS10:
|
||||
service->method = (SSL_METHOD*)TLSv1_server_method();
|
||||
break;
|
||||
#ifdef OPENSSL_1_0
|
||||
case SERVICE_TLS11:
|
||||
service->method = (SSL_METHOD*)TLSv1_1_server_method();
|
||||
break;
|
||||
case SERVICE_TLS12:
|
||||
service->method = (SSL_METHOD*)TLSv1_2_server_method();
|
||||
break;
|
||||
|
||||
#endif
|
||||
/** Rest of these use the maximum available SSL/TLS methods */
|
||||
case SERVICE_SSL_MAX:
|
||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
|
||||
@ -64,7 +64,7 @@ int buflen;
|
||||
ss_info_dassert(!dcb_isvalid(dcb), "Freed DCB must not be valid");
|
||||
ss_dfprintf(stderr, "\t..done\nMake clone DCB a zombie");
|
||||
clone->state = DCB_STATE_NOPOLLING;
|
||||
dcb_add_to_zombieslist(clone);
|
||||
dcb_close(clone);
|
||||
ss_info_dassert(dcb_get_zombies() == clone, "Clone DCB must be start of zombie list now");
|
||||
ss_dfprintf(stderr, "\t..done\nProcess the zombies list");
|
||||
dcb_process_zombies(0);
|
||||
|
||||
@ -331,7 +331,6 @@ const char *gw_dcb_state2string(int); /* DCB state to string */
|
||||
void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
|
||||
int dcb_isclient(DCB *); /* the DCB is the client of the session */
|
||||
void dcb_hashtable_stats(DCB *, void *); /**< Print statisitics */
|
||||
void dcb_add_to_zombieslist(DCB* dcb);
|
||||
int dcb_add_callback(DCB *, DCB_REASON, int (*)(struct dcb *, DCB_REASON, void *),
|
||||
void *);
|
||||
int dcb_remove_callback(DCB *, DCB_REASON, int (*)(struct dcb *, DCB_REASON, void *),
|
||||
@ -340,7 +339,6 @@ int dcb_isvalid(DCB *); /* Check the DCB is in the linked list */
|
||||
int dcb_count_by_usage(DCB_USAGE); /* Return counts of DCBs */
|
||||
int dcb_persistent_clean_count(DCB *, bool); /* Clean persistent and return count */
|
||||
|
||||
bool dcb_set_state(DCB* dcb, dcb_state_t new_state, dcb_state_t* old_state);
|
||||
void dcb_call_foreach (struct server* server, DCB_REASON reason);
|
||||
size_t dcb_get_session_id(DCB* dcb);
|
||||
bool dcb_get_ses_log_info(DCB* dcb, size_t* sesid, int* enabled_logs);
|
||||
|
||||
@ -124,6 +124,7 @@ typedef enum
|
||||
typedef struct monitor_servers {
|
||||
SERVER *server; /**< The server being monitored */
|
||||
MYSQL *con; /**< The MySQL connection */
|
||||
bool log_version_err;
|
||||
int mon_err_count;
|
||||
unsigned int mon_prev_status;
|
||||
unsigned int pending_status; /**< Pending Status flag bitmap */
|
||||
|
||||
@ -117,8 +117,10 @@ typedef enum {
|
||||
enum{
|
||||
SERVICE_SSLV3,
|
||||
SERVICE_TLS10,
|
||||
#ifdef OPENSSL_1_0
|
||||
SERVICE_TLS11,
|
||||
SERVICE_TLS12,
|
||||
#endif
|
||||
SERVICE_SSL_MAX,
|
||||
SERVICE_TLS_MAX,
|
||||
SERVICE_SSL_TLS_MAX
|
||||
|
||||
@ -24,8 +24,9 @@
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 02/04/14 Mark Riddoch Initial implementation
|
||||
* Date Who Description
|
||||
* 02/04/14 Mark Riddoch Initial implementation
|
||||
* 11/05/15 Massimilaino Pinto Added mariadb10_compat to master and slave structs
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -176,6 +177,7 @@ typedef struct router_slave {
|
||||
uint32_t lastEventTimestamp;/*< Last event timestamp sent */
|
||||
SPINLOCK catch_lock; /*< Event catchup lock */
|
||||
unsigned int cstate; /*< Catch up state */
|
||||
bool mariadb10_compat;/*< MariaDB 10.0 compatibility */
|
||||
SPINLOCK rses_lock; /*< Protects rses_deleted */
|
||||
pthread_t pthread;
|
||||
struct router_instance
|
||||
@ -234,6 +236,7 @@ typedef struct {
|
||||
GWBUF *selectvercom; /*< select @@version_comment */
|
||||
GWBUF *selecthostname;/*< select @@hostname */
|
||||
GWBUF *map; /*< select @@max_allowed_packet */
|
||||
GWBUF *mariadb10; /*< set @mariadb_slave_capability */
|
||||
uint8_t *fde_event; /*< Format Description Event */
|
||||
int fde_len; /*< Length of fde_event */
|
||||
} MASTER_RESPONSES;
|
||||
@ -242,54 +245,54 @@ typedef struct {
|
||||
* The per instance data for the router.
|
||||
*/
|
||||
typedef struct router_instance {
|
||||
SERVICE *service; /*< Pointer to the service using this router */
|
||||
ROUTER_SLAVE *slaves; /*< Link list of all the slave connections */
|
||||
SPINLOCK lock; /*< Spinlock for the instance data */
|
||||
char *uuid; /*< UUID for the router to use w/master */
|
||||
int masterid; /*< Server ID of the master */
|
||||
int serverid; /*< Server ID to use with master */
|
||||
int initbinlog; /*< Initial binlog file number */
|
||||
char *user; /*< User name to use with master */
|
||||
char *password; /*< Password to use with master */
|
||||
char *fileroot; /*< Root of binlog filename */
|
||||
bool master_chksum;/*< Does the master provide checksums */
|
||||
char *master_uuid; /*< UUID of the master */
|
||||
DCB *master; /*< DCB for master connection */
|
||||
DCB *client; /*< DCB for dummy client */
|
||||
SESSION *session; /*< Fake session for master connection */
|
||||
unsigned int master_state; /*< State of the master FSM */
|
||||
uint8_t lastEventReceived;
|
||||
uint32_t lastEventTimestamp; /*< Timestamp from last event */
|
||||
GWBUF *residual; /*< Any residual binlog event */
|
||||
MASTER_RESPONSES saved_master; /*< Saved master responses */
|
||||
char *binlogdir; /*< The directory with the binlog files */
|
||||
SPINLOCK binlog_lock; /*< Lock to control update of the binlog position */
|
||||
char binlog_name[BINLOG_FNAMELEN+1];
|
||||
SERVICE *service; /*< Pointer to the service using this router */
|
||||
ROUTER_SLAVE *slaves; /*< Link list of all the slave connections */
|
||||
SPINLOCK lock; /*< Spinlock for the instance data */
|
||||
char *uuid; /*< UUID for the router to use w/master */
|
||||
int masterid; /*< Server ID of the master */
|
||||
int serverid; /*< Server ID to use with master */
|
||||
int initbinlog; /*< Initial binlog file number */
|
||||
char *user; /*< User name to use with master */
|
||||
char *password; /*< Password to use with master */
|
||||
char *fileroot; /*< Root of binlog filename */
|
||||
bool master_chksum; /*< Does the master provide checksums */
|
||||
bool mariadb10_compat; /*< MariaDB 10.0 compatibility */
|
||||
char *master_uuid; /*< UUID of the master */
|
||||
DCB *master; /*< DCB for master connection */
|
||||
DCB *client; /*< DCB for dummy client */
|
||||
SESSION *session; /*< Fake session for master connection */
|
||||
unsigned int master_state; /*< State of the master FSM */
|
||||
uint8_t lastEventReceived;
|
||||
uint32_t lastEventTimestamp; /*< Timestamp from last event */
|
||||
GWBUF *residual; /*< Any residual binlog event */
|
||||
MASTER_RESPONSES saved_master; /*< Saved master responses */
|
||||
char *binlogdir; /*< The directory with the binlog files */
|
||||
SPINLOCK binlog_lock; /*< Lock to control update of the binlog position */
|
||||
char binlog_name[BINLOG_FNAMELEN+1];
|
||||
/*< Name of the current binlog file */
|
||||
uint64_t binlog_position;
|
||||
uint64_t binlog_position;
|
||||
/*< Current binlog position */
|
||||
int binlog_fd; /*< File descriptor of the binlog
|
||||
int binlog_fd; /*< File descriptor of the binlog
|
||||
* file being written
|
||||
*/
|
||||
uint64_t last_written; /*< Position of last event written */
|
||||
char prevbinlog[BINLOG_FNAMELEN+1];
|
||||
int rotating; /*< Rotation in progress flag */
|
||||
BLFILE *files; /*< Files used by the slaves */
|
||||
SPINLOCK fileslock; /*< Lock for the files queue above */
|
||||
unsigned int low_water; /*< Low water mark for client DCB */
|
||||
unsigned int high_water; /*< High water mark for client DCB */
|
||||
unsigned int short_burst; /*< Short burst for slave catchup */
|
||||
unsigned int long_burst; /*< Long burst for slave catchup */
|
||||
unsigned long burst_size; /*< Maximum size of burst to send */
|
||||
unsigned long heartbeat; /*< Configured heartbeat value */
|
||||
ROUTER_STATS stats; /*< Statistics for this router */
|
||||
int active_logs;
|
||||
int reconnect_pending;
|
||||
int retry_backoff;
|
||||
time_t connect_time;
|
||||
int handling_threads;
|
||||
struct router_instance
|
||||
*next;
|
||||
uint64_t last_written; /*< Position of last event written */
|
||||
char prevbinlog[BINLOG_FNAMELEN+1];
|
||||
int rotating; /*< Rotation in progress flag */
|
||||
BLFILE *files; /*< Files used by the slaves */
|
||||
SPINLOCK fileslock; /*< Lock for the files queue above */
|
||||
unsigned int low_water; /*< Low water mark for client DCB */
|
||||
unsigned int high_water; /*< High water mark for client DCB */
|
||||
unsigned int short_burst; /*< Short burst for slave catchup */
|
||||
unsigned int long_burst; /*< Long burst for slave catchup */
|
||||
unsigned long burst_size; /*< Maximum size of burst to send */
|
||||
unsigned long heartbeat; /*< Configured heartbeat value */
|
||||
ROUTER_STATS stats; /*< Statistics for this router */
|
||||
int active_logs;
|
||||
int reconnect_pending;
|
||||
int retry_backoff;
|
||||
time_t connect_time;
|
||||
int handling_threads;
|
||||
struct router_instance *next;
|
||||
} ROUTER_INSTANCE;
|
||||
|
||||
/**
|
||||
@ -315,15 +318,16 @@ typedef struct router_instance {
|
||||
#define BLRM_MAP 0x0011
|
||||
#define BLRM_REGISTER 0x0012
|
||||
#define BLRM_BINLOGDUMP 0x0013
|
||||
#define BLRM_MARIADB10 0x0014
|
||||
|
||||
#define BLRM_MAXSTATE 0x0013
|
||||
#define BLRM_MAXSTATE 0x0014
|
||||
|
||||
static char *blrm_states[] = { "Unconnected", "Connecting", "Authenticated", "Timestamp retrieval",
|
||||
"Server ID retrieval", "HeartBeat Period setup", "binlog checksum config",
|
||||
"binlog checksum rerieval", "GTID Mode retrieval", "Master UUID retrieval",
|
||||
"Set Slave UUID", "Set Names latin1", "Set Names utf8", "select 1",
|
||||
"select version()", "select @@version_comment", "select @@hostname",
|
||||
"select @@mx_allowed_packet", "Register slave", "Binlog Dump" };
|
||||
"select @@mx_allowed_packet", "Register slave", "Binlog Dump", "Set MariaDB slave capability" };
|
||||
|
||||
#define BLRS_CREATED 0x0000
|
||||
#define BLRS_UNREGISTERED 0x0001
|
||||
@ -397,6 +401,7 @@ static char *blrs_states[] = { "Created", "Unregistered", "Registered",
|
||||
#define PREVIOUS_GTIDS_EVENT 0x23
|
||||
|
||||
#define MAX_EVENT_TYPE 0x23
|
||||
#define MAX_EVENT_TYPE_MARIADB10 0xa3
|
||||
|
||||
/**
|
||||
* Binlog event flags
|
||||
|
||||
@ -252,6 +252,7 @@ typedef struct rwsplit_config_st {
|
||||
int rw_max_sescmd_history_size;
|
||||
bool disable_sescmd_hist;
|
||||
bool disable_slave_recovery;
|
||||
bool master_reads; /*< Use master for reads */
|
||||
} rwsplit_config_t;
|
||||
|
||||
|
||||
|
||||
@ -245,4 +245,6 @@ typedef struct router_instance {
|
||||
#define BACKEND_TYPE(b) (SERVER_IS_MASTER((b)->backend_server) ? BE_MASTER : \
|
||||
(SERVER_IS_SLAVE((b)->backend_server) ? BE_SLAVE : BE_UNDEFINED));
|
||||
|
||||
bool subsvc_is_valid(SUBSERVICE*);
|
||||
|
||||
#endif /*< _SHARDROUTER_H */
|
||||
|
||||
@ -155,7 +155,10 @@ startMonitor(void *arg,void* opt)
|
||||
else if(!strcmp(params->name,"script"))
|
||||
{
|
||||
if(handle->script)
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = NULL;
|
||||
}
|
||||
|
||||
if(access(params->value,X_OK) == 0)
|
||||
{
|
||||
@ -277,7 +280,7 @@ monitorDatabase(MONITOR *mon, MONITOR_SERVERS *database)
|
||||
{
|
||||
GALERA_MONITOR* handle = (GALERA_MONITOR*)mon->handle;
|
||||
MYSQL_ROW row;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_RES *result,*result2;
|
||||
int isjoined = 0;
|
||||
char *uname = mon->user;
|
||||
char *passwd = mon->password;
|
||||
@ -369,6 +372,14 @@ char *server_string;
|
||||
if (mysql_query(database->con, "SHOW STATUS LIKE 'wsrep_local_state'") == 0
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
if(mysql_field_count(database->con) < 2)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'wsrep_local_state'\". Expected 2 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if (strcmp(row[1], "4") == 0)
|
||||
@ -377,13 +388,22 @@ char *server_string;
|
||||
/* Check if the node is a donor and is using xtrabackup, in this case it can stay alive */
|
||||
else if (strcmp(row[1], "2") == 0 && handle->availableWhenDonor == 1) {
|
||||
if (mysql_query(database->con, "SHOW VARIABLES LIKE 'wsrep_sst_method'") == 0
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
&& (result2 = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
if(mysql_field_count(database->con) < 2)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
mysql_free_result(result2);
|
||||
skygw_log_write(LE,"Error: Unexpected result for \"SHOW VARIABLES LIKE 'wsrep_sst_method'\". Expected 2 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if (strncmp(row[1], "xtrabackup", 10) == 0)
|
||||
isjoined = 1;
|
||||
}
|
||||
mysql_free_result(result2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -395,6 +415,15 @@ char *server_string;
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
long local_index = -1;
|
||||
|
||||
if(mysql_field_count(database->con) < 2)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'wsrep_local_index'\". Expected 2 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
local_index = strtol(row[1], NULL, 10);
|
||||
|
||||
@ -366,7 +366,15 @@ char *server_string;
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
long server_id = -1;
|
||||
|
||||
|
||||
if(mysql_field_count(database->con) != 1)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: Unexpected result for 'SELECT @@server_id'. Expected 1 column."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
server_id = strtol(row[0], NULL, 10);
|
||||
@ -392,7 +400,16 @@ char *server_string;
|
||||
{
|
||||
int i = 0;
|
||||
long master_id = -1;
|
||||
|
||||
|
||||
if(mysql_field_count(database->con) < 42)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: \"SHOW ALL SLAVES STATUS\" "
|
||||
"returned less than the expected amount of columns. Expected 42 columns"
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
/* get Slave_IO_Running and Slave_SQL_Running values*/
|
||||
@ -431,7 +448,31 @@ char *server_string;
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
long master_id = -1;
|
||||
|
||||
|
||||
if(mysql_field_count(database->con) < 40)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
|
||||
if(server_version < 5*10000 + 5*100)
|
||||
{
|
||||
if(database->log_version_err)
|
||||
{
|
||||
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
|
||||
" for versions less than 5.5 does not have master_server_id, "
|
||||
"replication tree cannot be resolved for server %s."
|
||||
" MySQL Version: %s",database->server->unique_name,version_str);
|
||||
database->log_version_err = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
|
||||
"returned less than the expected amount of columns. Expected 40 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
/* get Slave_IO_Running and Slave_SQL_Running values*/
|
||||
@ -463,6 +504,13 @@ char *server_string;
|
||||
if (mysql_query(database->con, "SHOW GLOBAL VARIABLES LIKE 'read_only'") == 0
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
if(mysql_field_count(database->con) < 2)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: Unexpected result for \"SHOW GLOBAL VARIABLES LIKE 'read_only'\". Expected 2 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
|
||||
@ -408,6 +408,13 @@ char *server_string;
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
long server_id = -1;
|
||||
if(mysql_field_count(database->con) != 1)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: Unexpected result for \"SELECT @@server_id\". Expected 1 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
server_id = strtol(row[0], NULL, 10);
|
||||
@ -433,6 +440,16 @@ char *server_string;
|
||||
{
|
||||
int i = 0;
|
||||
long master_id = -1;
|
||||
|
||||
if(mysql_field_count(database->con) < 42)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: \"SHOW ALL SLAVES STATUS\" "
|
||||
"returned less than the expected amount of columns. Expected 42 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
/* get Slave_IO_Running and Slave_SQL_Running values*/
|
||||
@ -471,6 +488,29 @@ char *server_string;
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
long master_id = -1;
|
||||
if(mysql_field_count(database->con) < 40)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
if(server_version < 5*10000 + 5*100)
|
||||
{
|
||||
if(database->log_version_err)
|
||||
{
|
||||
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
|
||||
" for versions less than 5.5 does not have master_server_id, "
|
||||
"replication tree cannot be resolved for server %s."
|
||||
" MySQL Version: %s",database->server->unique_name,version_str);
|
||||
database->log_version_err = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE,"Error: \"SHOW SLAVE STATUS\" "
|
||||
"returned less than the expected amount of columns. Expected 40 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
/* get Slave_IO_Running and Slave_SQL_Running values*/
|
||||
|
||||
@ -323,6 +323,14 @@ char *server_string;
|
||||
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'") == 0
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
if(mysql_field_count(database->con) < 2)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'\". Expected 2 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if (atoi(row[1]) > 0)
|
||||
@ -335,6 +343,14 @@ char *server_string;
|
||||
if (mysql_query(database->con, "SHOW STATUS LIKE 'Ndb_cluster_node_id'") == 0
|
||||
&& (result = mysql_store_result(database->con)) != NULL)
|
||||
{
|
||||
if(mysql_field_count(database->con) < 2)
|
||||
{
|
||||
mysql_free_result(result);
|
||||
skygw_log_write(LE,"Error: Unexpected result for \"SHOW STATUS LIKE 'Ndb_cluster_node_id'\". Expected 2 columns."
|
||||
" MySQL Version: %s",version_str);
|
||||
return;
|
||||
}
|
||||
|
||||
long cluster_node_id = -1;
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
|
||||
@ -58,6 +58,7 @@ extern __thread log_info_t tls_log_info;
|
||||
* Revision History
|
||||
* Date Who Description
|
||||
* 13/06/2014 Mark Riddoch Initial implementation
|
||||
* 07/07/15 Martin Brampton Correct failure handling
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -270,9 +271,7 @@ int n_connect = 0;
|
||||
{
|
||||
atomic_add(&dcb->stats.n_accepts, 1);
|
||||
client_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
|
||||
|
||||
if (client_dcb == NULL)
|
||||
|
||||
{
|
||||
close(so);
|
||||
return n_connect;
|
||||
@ -283,7 +282,8 @@ int n_connect = 0;
|
||||
if ((maxscaled_pr = (MAXSCALED *)malloc(sizeof(MAXSCALED))) == NULL)
|
||||
{
|
||||
client_dcb->protocol = NULL;
|
||||
dcb_add_to_zombieslist(client_dcb);
|
||||
close(so);
|
||||
dcb_close(client_dcb);
|
||||
return n_connect;
|
||||
}
|
||||
maxscaled_pr->username = NULL;
|
||||
@ -293,9 +293,9 @@ int n_connect = 0;
|
||||
client_dcb->session =
|
||||
session_alloc(dcb->session->service, client_dcb);
|
||||
|
||||
if (poll_add_dcb(client_dcb) == -1)
|
||||
if (poll_add_dcb(client_dcb))
|
||||
{
|
||||
dcb_add_to_zombieslist(dcb);
|
||||
dcb_close(dcb);
|
||||
return n_connect;
|
||||
}
|
||||
n_connect++;
|
||||
|
||||
@ -1452,8 +1452,8 @@ int gw_MySQLListener(
|
||||
// add listening socket to poll structure
|
||||
if (poll_add_dcb(listen_dcb) == -1) {
|
||||
fprintf(stderr,
|
||||
"\n* Failed to start polling the socket due error "
|
||||
"%i, %s.\n\n",
|
||||
"\n* MaxScale encountered system limit while "
|
||||
"attempting to register on an epoll instance.\n\n",
|
||||
errno,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
@ -1688,7 +1688,8 @@ int gw_MySQLAccept(DCB *listener)
|
||||
client_dcb,
|
||||
1,
|
||||
0,
|
||||
"MaxScale internal error.");
|
||||
"MaxScale encountered system limit while "
|
||||
"attempting to register on an epoll instance.");
|
||||
|
||||
/** close client_dcb */
|
||||
dcb_close(client_dcb);
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
* 03/10/2014 Massimiliano Pinto Added netmask for wildcard in IPv4 hosts.
|
||||
* 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
|
||||
* 07/07/15 Martin Brampton Fix problem recognising null password
|
||||
*
|
||||
*/
|
||||
|
||||
@ -1550,13 +1551,6 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
break;
|
||||
}
|
||||
|
||||
/** See if ANYDB == Y */
|
||||
if(key.resource)
|
||||
{
|
||||
key.resource = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!user_password) {
|
||||
/*
|
||||
* user@% not found.
|
||||
|
||||
@ -67,6 +67,7 @@ extern __thread log_info_t tls_log_info;
|
||||
* Date Who Description
|
||||
* 17/06/2013 Mark Riddoch Initial version
|
||||
* 17/07/2013 Mark Riddoch Addition of login phase
|
||||
* 07/07/2015 Martin Brampton Call unified dcb_close on error
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -315,13 +316,13 @@ int n_connect = 0;
|
||||
|
||||
if (telnetd_pr == NULL)
|
||||
{
|
||||
dcb_add_to_zombieslist(client_dcb);
|
||||
dcb_close(client_dcb);
|
||||
return n_connect;
|
||||
}
|
||||
|
||||
if (poll_add_dcb(client_dcb) == -1)
|
||||
if (poll_add_dcb(client_dcb))
|
||||
{
|
||||
dcb_add_to_zombieslist(dcb);
|
||||
dcb_close(dcb);
|
||||
return n_connect;
|
||||
}
|
||||
n_connect++;
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
* 02/04/2014 Mark Riddoch Initial implementation
|
||||
* 17/02/2015 Massimiliano Pinto Addition of slave port and username in diagnostics
|
||||
* 18/02/2015 Massimiliano Pinto Addition of dcb_close in closeSession
|
||||
* 07/05/2015 Massimiliano Pinto Addition of MariaDB 10 compatibility support
|
||||
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -195,6 +197,7 @@ unsigned char *defuuid;
|
||||
inst->retry_backoff = 1;
|
||||
inst->binlogdir = NULL;
|
||||
inst->heartbeat = 300; // Default is every 5 minutes
|
||||
inst->mariadb10_compat = false;
|
||||
|
||||
inst->user = strdup(service->credentials.name);
|
||||
inst->password = strdup(service->credentials.authdata);
|
||||
@ -282,6 +285,10 @@ unsigned char *defuuid;
|
||||
{
|
||||
inst->masterid = atoi(value);
|
||||
}
|
||||
else if (strcmp(options[i], "mariadb10-compatibility") == 0)
|
||||
{
|
||||
inst->mariadb10_compat = config_truth_value(value);
|
||||
}
|
||||
else if (strcmp(options[i], "filestem") == 0)
|
||||
{
|
||||
inst->fileroot = strdup(value);
|
||||
@ -388,6 +395,7 @@ unsigned char *defuuid;
|
||||
inst->saved_master.selectvercom = blr_cache_read_response(inst, "selectvercom");
|
||||
inst->saved_master.selecthostname = blr_cache_read_response(inst, "selecthostname");
|
||||
inst->saved_master.map = blr_cache_read_response(inst, "map");
|
||||
inst->saved_master.mariadb10 = blr_cache_read_response(inst, "mariadb10");
|
||||
|
||||
/*
|
||||
* Initialise the binlog file and position
|
||||
@ -490,6 +498,7 @@ ROUTER_SLAVE *slave;
|
||||
strcpy(slave->binlogfile, "unassigned");
|
||||
slave->connect_time = time(0);
|
||||
slave->lastEventTimestamp = 0;
|
||||
slave->mariadb10_compat = false;
|
||||
|
||||
/**
|
||||
* Add this session to the list of active sessions.
|
||||
|
||||
@ -23,8 +23,9 @@
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* Date Who Description
|
||||
* 14/04/2014 Mark Riddoch Initial implementation
|
||||
* 07/05/2015 Massimiliano Pinto Added MAX_EVENT_TYPE_MARIADB10
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -439,15 +440,26 @@ struct stat statb;
|
||||
hdr->next_pos = EXTRACT32(&hdbuf[13]);
|
||||
hdr->flags = EXTRACT16(&hdbuf[17]);
|
||||
|
||||
if (hdr->event_type > MAX_EVENT_TYPE)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR,
|
||||
"Invalid event type 0x%x. "
|
||||
if (router->mariadb10_compat) {
|
||||
if (hdr->event_type > MAX_EVENT_TYPE_MARIADB10) {
|
||||
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR,
|
||||
"Invalid MariaDB 10 event type 0x%x. "
|
||||
"Binlog file is %s, position %d",
|
||||
hdr->event_type,
|
||||
file->binlogname, pos)));
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (hdr->event_type > MAX_EVENT_TYPE) {
|
||||
LOGIF(LE, (skygw_log_write(LOGFILE_ERROR,
|
||||
"Invalid event type 0x%x. "
|
||||
"Binlog file is %s, position %d",
|
||||
hdr->event_type,
|
||||
file->binlogname, pos)));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (hdr->next_pos < pos && hdr->event_type != ROTATE_EVENT)
|
||||
{
|
||||
|
||||
@ -31,8 +31,9 @@
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* Date Who Description
|
||||
* 02/04/2014 Mark Riddoch Initial implementation
|
||||
* 07/05/2015 Massimiliano Pinto Added MariaDB 10 Compatibility
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -448,11 +449,27 @@ char query[128];
|
||||
GWBUF_CONSUME_ALL(router->saved_master.chksum2);
|
||||
router->saved_master.chksum2 = buf;
|
||||
blr_cache_response(router, "chksum2", buf);
|
||||
buf = blr_make_query("SELECT @@GLOBAL.GTID_MODE");
|
||||
router->master_state = BLRM_GTIDMODE;
|
||||
|
||||
if (router->mariadb10_compat) {
|
||||
buf = blr_make_query("SET @mariadb_slave_capability=4");
|
||||
router->master_state = BLRM_MARIADB10;
|
||||
} else {
|
||||
buf = blr_make_query("SELECT @@GLOBAL.GTID_MODE");
|
||||
router->master_state = BLRM_GTIDMODE;
|
||||
}
|
||||
router->master->func.write(router->master, buf);
|
||||
break;
|
||||
}
|
||||
case BLRM_MARIADB10:
|
||||
// Response to the SET @mariadb_slave_capability=4, should be stored
|
||||
if (router->saved_master.mariadb10)
|
||||
GWBUF_CONSUME_ALL(router->saved_master.mariadb10);
|
||||
router->saved_master.mariadb10 = buf;
|
||||
blr_cache_response(router, "mariadb10", buf);
|
||||
buf = blr_make_query("SHOW VARIABLES LIKE 'SERVER_UUID'");
|
||||
router->master_state = BLRM_MUUID;
|
||||
router->master->func.write(router->master, buf);
|
||||
break;
|
||||
case BLRM_GTIDMODE:
|
||||
// Response to the GTID_MODE, should be stored
|
||||
if (router->saved_master.gtid_mode)
|
||||
|
||||
@ -36,9 +36,12 @@
|
||||
* 18/02/2015 Massimiliano Pinto Addition of DISCONNECT ALL and DISCONNECT SERVER server_id
|
||||
* 18/03/2015 Markus Makela Better detection of CRC32 | NONE checksum
|
||||
* 19/03/2015 Massimiliano Pinto Addition of basic MariaDB 10 compatibility support
|
||||
* 07/05/2015 Massimiliano Pinto Added MariaDB 10 Compatibility
|
||||
* 11/05/2015 Massimiliano Pinto Only MariaDB 10 Slaves can register to binlog router with a MariaDB 10 Master
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -123,7 +126,28 @@ blr_slave_request(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue)
|
||||
return blr_slave_query(router, slave, queue);
|
||||
break;
|
||||
case COM_REGISTER_SLAVE:
|
||||
return blr_slave_register(router, slave, queue);
|
||||
/*
|
||||
* If Master is MariaDB10 don't allow registration from
|
||||
* MariaDB/Mysql 5 Slaves
|
||||
*/
|
||||
|
||||
if (router->mariadb10_compat && !slave->mariadb10_compat) {
|
||||
slave->state = BLRS_ERRORED;
|
||||
blr_send_custom_error(slave->dcb, 1, 0,
|
||||
"MariaDB 10 Slave is required for Slave registration");
|
||||
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"%s: Slave %s: a MariaDB 10 Slave is required for Slave registration",
|
||||
router->service->name,
|
||||
slave->dcb->remote)));
|
||||
|
||||
dcb_close(slave->dcb);
|
||||
return 1;
|
||||
} else {
|
||||
/* Master and Slave version OK: continue with slave registration */
|
||||
return blr_slave_register(router, slave, queue);
|
||||
}
|
||||
break;
|
||||
case COM_BINLOG_DUMP:
|
||||
return blr_slave_binlog_dump(router, slave, queue);
|
||||
@ -366,10 +390,17 @@ int query_len;
|
||||
free(query_text);
|
||||
return blr_slave_replay(router, slave, router->saved_master.heartbeat);
|
||||
}
|
||||
else if (strcasecmp(word, "@mariadb_slave_capability") == 0)
|
||||
else if (strcasecmp(word, "@mariadb_slave_capability") == 0)
|
||||
{
|
||||
free(query_text);
|
||||
return blr_slave_send_ok(router, slave);
|
||||
/* mariadb10 compatibility is set for the slave */
|
||||
slave->mariadb10_compat=true;
|
||||
|
||||
free(query_text);
|
||||
if (router->mariadb10_compat) {
|
||||
return blr_slave_replay(router, slave, router->saved_master.mariadb10);
|
||||
} else {
|
||||
return blr_slave_send_ok(router, slave);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(word, "@master_binlog_checksum") == 0)
|
||||
{
|
||||
@ -442,7 +473,7 @@ int query_len;
|
||||
|
||||
query_text = strndup(qtext, query_len);
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR, "Unexpected query from slave server %s", query_text)));
|
||||
LOGFILE_ERROR, "Unexpected query from slave %s: %s", slave->dcb->remote, query_text)));
|
||||
free(query_text);
|
||||
blr_slave_send_error(router, slave, "Unexpected SQL query received from slave.");
|
||||
return 1;
|
||||
|
||||
@ -113,14 +113,10 @@ MAXINFO_TREE *col, *table;
|
||||
#endif
|
||||
default:
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
if (tree)
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
*parse_error = PARSE_SYNTAX_ERROR;
|
||||
if (tree)
|
||||
free_tree(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -226,7 +226,7 @@ static rses_property_t* mysql_sescmd_get_property(
|
||||
static rses_property_t* rses_property_init(
|
||||
rses_property_type_t prop_type);
|
||||
|
||||
static void rses_property_add(
|
||||
static int rses_property_add(
|
||||
ROUTER_CLIENT_SES* rses,
|
||||
rses_property_t* prop);
|
||||
|
||||
@ -287,7 +287,7 @@ static sescmd_cursor_t* backend_ref_get_sescmd_cursor (backend_ref_t* bref);
|
||||
static int router_handle_state_switch(DCB* dcb, DCB_REASON reason, void* data);
|
||||
static bool handle_error_new_connection(
|
||||
ROUTER_INSTANCE* inst,
|
||||
ROUTER_CLIENT_SES* rses,
|
||||
ROUTER_CLIENT_SES** rses,
|
||||
DCB* backend_dcb,
|
||||
GWBUF* errmsg);
|
||||
static void handle_error_reply_client(
|
||||
@ -1243,7 +1243,8 @@ static bool get_dcb(
|
||||
SERVER_IS_SLAVE(b->backend_server) &&
|
||||
(max_rlag == MAX_RLAG_UNDEFINED ||
|
||||
(b->backend_server->rlag != MAX_RLAG_NOT_AVAILABLE &&
|
||||
b->backend_server->rlag <= max_rlag)))
|
||||
b->backend_server->rlag <= max_rlag)) &&
|
||||
!rses->rses_config.master_reads)
|
||||
{
|
||||
/** found slave */
|
||||
candidate_bref = &backend_ref[i];
|
||||
@ -2941,6 +2942,11 @@ static void bref_clear_state(
|
||||
backend_ref_t* bref,
|
||||
bref_state_t state)
|
||||
{
|
||||
if(bref == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to bref_clear_state. (%s:%d)",__FILE__,__LINE__);
|
||||
return;
|
||||
}
|
||||
if (state != BREF_WAITING_RESULT)
|
||||
{
|
||||
bref->bref_state &= ~state;
|
||||
@ -2970,6 +2976,11 @@ static void bref_set_state(
|
||||
backend_ref_t* bref,
|
||||
bref_state_t state)
|
||||
{
|
||||
if(bref == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to bref_set_state. (%s:%d)",__FILE__,__LINE__);
|
||||
return;
|
||||
}
|
||||
if (state != BREF_WAITING_RESULT)
|
||||
{
|
||||
bref->bref_state |= state;
|
||||
@ -3533,7 +3544,8 @@ static rses_property_t* rses_property_init(
|
||||
prop = (rses_property_t*)calloc(1, sizeof(rses_property_t));
|
||||
if (prop == NULL)
|
||||
{
|
||||
goto return_prop;
|
||||
skygw_log_write(LE,"Error: Malloc returned NULL. (%s:%d)",__FILE__,__LINE__);
|
||||
return NULL;
|
||||
}
|
||||
prop->rses_prop_type = prop_type;
|
||||
#if defined(SS_DEBUG)
|
||||
@ -3541,7 +3553,6 @@ static rses_property_t* rses_property_init(
|
||||
prop->rses_prop_chk_tail = CHK_NUM_ROUTER_PROPERTY;
|
||||
#endif
|
||||
|
||||
return_prop:
|
||||
CHK_RSES_PROP(prop);
|
||||
return prop;
|
||||
}
|
||||
@ -3552,6 +3563,11 @@ return_prop:
|
||||
static void rses_property_done(
|
||||
rses_property_t* prop)
|
||||
{
|
||||
if(prop == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to rses_property_done. (%s:%d)",__FILE__,__LINE__);
|
||||
return;
|
||||
}
|
||||
CHK_RSES_PROP(prop);
|
||||
|
||||
switch (prop->rses_prop_type) {
|
||||
@ -3585,10 +3601,20 @@ static void rses_property_done(
|
||||
*
|
||||
* Router client session must be locked.
|
||||
*/
|
||||
static void rses_property_add(
|
||||
static int rses_property_add(
|
||||
ROUTER_CLIENT_SES* rses,
|
||||
rses_property_t* prop)
|
||||
{
|
||||
if(rses == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: Router client session is NULL. (%s:%d)",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
if(prop == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: Router client session property is NULL. (%s:%d)",__FILE__,__LINE__);
|
||||
return -1;
|
||||
}
|
||||
rses_property_t* p;
|
||||
|
||||
CHK_CLIENT_RSES(rses);
|
||||
@ -3610,6 +3636,7 @@ static void rses_property_add(
|
||||
}
|
||||
p->rses_prop_next = prop;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3620,7 +3647,13 @@ static mysql_sescmd_t* rses_property_get_sescmd(
|
||||
rses_property_t* prop)
|
||||
{
|
||||
mysql_sescmd_t* sescmd;
|
||||
|
||||
|
||||
if(prop == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to rses_property_get_sescmd. (%s:%d)",__FILE__,__LINE__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CHK_RSES_PROP(prop);
|
||||
ss_dassert(prop->rses_prop_rsession == NULL ||
|
||||
SPINLOCK_IS_LOCKED(&prop->rses_prop_rsession->rses_lock));
|
||||
@ -3633,22 +3666,6 @@ static mysql_sescmd_t* rses_property_get_sescmd(
|
||||
}
|
||||
return sescmd;
|
||||
}
|
||||
|
||||
/**
|
||||
static void rses_begin_locked_property_action(
|
||||
rses_property_t* prop)
|
||||
{
|
||||
CHK_RSES_PROP(prop);
|
||||
spinlock_acquire(&prop->rses_prop_lock);
|
||||
}
|
||||
|
||||
static void rses_end_locked_property_action(
|
||||
rses_property_t* prop)
|
||||
{
|
||||
CHK_RSES_PROP(prop);
|
||||
spinlock_release(&prop->rses_prop_lock);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create session command property.
|
||||
@ -3681,6 +3698,11 @@ static mysql_sescmd_t* mysql_sescmd_init (
|
||||
static void mysql_sescmd_done(
|
||||
mysql_sescmd_t* sescmd)
|
||||
{
|
||||
if(sescmd == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to mysql_sescmd_done. (%s:%d)",__FILE__,__LINE__);
|
||||
return;
|
||||
}
|
||||
CHK_RSES_PROP(sescmd->my_sescmd_prop);
|
||||
gwbuf_free(sescmd->my_sescmd_buf);
|
||||
memset(sescmd, 0, sizeof(mysql_sescmd_t));
|
||||
@ -3763,7 +3785,7 @@ static GWBUF* sescmd_cursor_process_replies(
|
||||
dcb_close(bref->bref_dcb);
|
||||
*reconnect = true;
|
||||
if(replybuf)
|
||||
gwbuf_consume(replybuf,gwbuf_length(replybuf));
|
||||
while((replybuf = gwbuf_consume(replybuf,gwbuf_length(replybuf))));
|
||||
}
|
||||
}
|
||||
/** This is a response from the master and it is the "right" one.
|
||||
@ -3806,7 +3828,7 @@ static GWBUF* sescmd_cursor_process_replies(
|
||||
skygw_log_write(LOGFILE_DEBUG,"Slave '%s' responded faster to a session command.",
|
||||
bref->bref_backend->backend_server->unique_name);
|
||||
if(replybuf)
|
||||
gwbuf_free(replybuf);
|
||||
while((replybuf = gwbuf_consume(replybuf,gwbuf_length(replybuf))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3853,6 +3875,12 @@ static bool sescmd_cursor_is_active(
|
||||
sescmd_cursor_t* sescmd_cursor)
|
||||
{
|
||||
bool succp;
|
||||
|
||||
if(sescmd_cursor == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_is_active. (%s:%d)",__FILE__,__LINE__);
|
||||
return false;
|
||||
}
|
||||
ss_dassert(SPINLOCK_IS_LOCKED(&sescmd_cursor->scmd_cur_rses->rses_lock));
|
||||
|
||||
succp = sescmd_cursor->scmd_cur_active;
|
||||
@ -3878,6 +3906,11 @@ static GWBUF* sescmd_cursor_clone_querybuf(
|
||||
sescmd_cursor_t* scur)
|
||||
{
|
||||
GWBUF* buf;
|
||||
if(scur == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_clone_querybuf. (%s:%d)",__FILE__,__LINE__);
|
||||
return NULL;
|
||||
}
|
||||
ss_dassert(scur->scmd_cur_cmd != NULL);
|
||||
|
||||
buf = gwbuf_clone(scur->scmd_cur_cmd->my_sescmd_buf);
|
||||
@ -3890,7 +3923,12 @@ static bool sescmd_cursor_history_empty(
|
||||
sescmd_cursor_t* scur)
|
||||
{
|
||||
bool succp;
|
||||
|
||||
|
||||
if(scur == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_history_empty. (%s:%d)",__FILE__,__LINE__);
|
||||
return true;
|
||||
}
|
||||
CHK_SESCMD_CUR(scur);
|
||||
|
||||
if (scur->scmd_cur_rses->rses_properties[RSES_PROP_TYPE_SESCMD] == NULL)
|
||||
@ -3910,6 +3948,11 @@ static void sescmd_cursor_reset(
|
||||
sescmd_cursor_t* scur)
|
||||
{
|
||||
ROUTER_CLIENT_SES* rses;
|
||||
if(scur == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_reset. (%s:%d)",__FILE__,__LINE__);
|
||||
return;
|
||||
}
|
||||
CHK_SESCMD_CUR(scur);
|
||||
CHK_CLIENT_RSES(scur->scmd_cur_rses);
|
||||
rses = scur->scmd_cur_rses;
|
||||
@ -3926,6 +3969,11 @@ static bool execute_sescmd_history(
|
||||
{
|
||||
bool succp;
|
||||
sescmd_cursor_t* scur;
|
||||
if(bref == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to execute_sescmd_history. (%s:%d)",__FILE__,__LINE__);
|
||||
return false;
|
||||
}
|
||||
CHK_BACKEND_REF(bref);
|
||||
|
||||
scur = &bref->bref_sescmd_cur;
|
||||
@ -3961,7 +4009,12 @@ static bool execute_sescmd_in_backend(
|
||||
bool succp;
|
||||
int rc = 0;
|
||||
sescmd_cursor_t* scur;
|
||||
|
||||
GWBUF* buf;
|
||||
if(backend_ref == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to execute_sescmd_in_backend. (%s:%d)",__FILE__,__LINE__);
|
||||
return false;
|
||||
}
|
||||
if (BREF_IS_CLOSED(backend_ref))
|
||||
{
|
||||
succp = false;
|
||||
@ -3993,27 +4046,9 @@ static bool execute_sescmd_in_backend(
|
||||
/** Cursor is left active when function returns. */
|
||||
sescmd_cursor_set_active(scur, true);
|
||||
}
|
||||
#if defined(SS_DEBUG)
|
||||
LOGIF(LT, tracelog_routed_query(scur->scmd_cur_rses,
|
||||
"execute_sescmd_in_backend",
|
||||
backend_ref,
|
||||
sescmd_cursor_clone_querybuf(scur)));
|
||||
|
||||
{
|
||||
GWBUF* tmpbuf = sescmd_cursor_clone_querybuf(scur);
|
||||
uint8_t* ptr = GWBUF_DATA(tmpbuf);
|
||||
unsigned char cmd = MYSQL_GET_COMMAND(ptr);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [execute_sescmd_in_backend] Just before write, fd "
|
||||
"%d : cmd %s.",
|
||||
pthread_self(),
|
||||
dcb->fd,
|
||||
STRPACKETTYPE(cmd))));
|
||||
gwbuf_free(tmpbuf);
|
||||
}
|
||||
#endif /*< SS_DEBUG */
|
||||
buf = sescmd_cursor_clone_querybuf(scur);
|
||||
|
||||
switch (scur->scmd_cur_cmd->my_sescmd_packet_type) {
|
||||
case MYSQL_COM_CHANGE_USER:
|
||||
/** This makes it possible to handle replies correctly */
|
||||
@ -4022,7 +4057,7 @@ static bool execute_sescmd_in_backend(
|
||||
dcb,
|
||||
NULL,
|
||||
dcb->session,
|
||||
sescmd_cursor_clone_querybuf(scur));
|
||||
buf);
|
||||
break;
|
||||
|
||||
case MYSQL_COM_INIT_DB:
|
||||
@ -4048,10 +4083,11 @@ static bool execute_sescmd_in_backend(
|
||||
* Mark session command buffer, it triggers writing
|
||||
* MySQL command to protocol
|
||||
*/
|
||||
|
||||
gwbuf_set_type(scur->scmd_cur_cmd->my_sescmd_buf, GWBUF_TYPE_SESCMD);
|
||||
rc = dcb->func.write(
|
||||
dcb,
|
||||
sescmd_cursor_clone_querybuf(scur));
|
||||
buf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4061,6 +4097,7 @@ static bool execute_sescmd_in_backend(
|
||||
}
|
||||
else
|
||||
{
|
||||
while((buf = GWBUF_CONSUME_ALL(buf)) != NULL);
|
||||
succp = false;
|
||||
}
|
||||
return_succp:
|
||||
@ -4082,6 +4119,12 @@ static bool sescmd_cursor_next(
|
||||
rses_property_t* prop_curr;
|
||||
rses_property_t* prop_next;
|
||||
|
||||
if(scur == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: NULL parameter passed to sescmd_cursor_next. (%s:%d)",__FILE__,__LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
ss_dassert(scur != NULL);
|
||||
ss_dassert(*(scur->scmd_cur_ptr_property) != NULL);
|
||||
ss_dassert(SPINLOCK_IS_LOCKED(
|
||||
@ -4408,11 +4451,21 @@ static bool route_session_write(
|
||||
* prevent it from being released before properties
|
||||
* are cleaned up as a part of router sessionclean-up.
|
||||
*/
|
||||
prop = rses_property_init(RSES_PROP_TYPE_SESCMD);
|
||||
if((prop = rses_property_init(RSES_PROP_TYPE_SESCMD)) == NULL)
|
||||
{
|
||||
skygw_log_write(LE,"Error: Router session property initialization failed");
|
||||
rses_end_locked_router_action(router_cli_ses);
|
||||
return false;
|
||||
}
|
||||
mysql_sescmd_init(prop, querybuf, packet_type, router_cli_ses);
|
||||
|
||||
/** Add sescmd property to router client session */
|
||||
rses_property_add(router_cli_ses, prop);
|
||||
if(rses_property_add(router_cli_ses, prop) != 0)
|
||||
{
|
||||
skygw_log_write(LE,"Error: Session property addition failed.");
|
||||
rses_end_locked_router_action(router_cli_ses);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i=0; i<router_cli_ses->rses_nbackends; i++)
|
||||
{
|
||||
@ -4535,7 +4588,10 @@ static void rwsplit_process_router_options(
|
||||
int i;
|
||||
char* value;
|
||||
select_criteria_t c;
|
||||
|
||||
|
||||
if(options == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; options[i]; i++)
|
||||
{
|
||||
if ((value = strchr(options[i], '=')) == NULL)
|
||||
@ -4588,6 +4644,10 @@ static void rwsplit_process_router_options(
|
||||
{
|
||||
router->rwsplit_config.disable_slave_recovery = config_truth_value(value);
|
||||
}
|
||||
else if(strcmp(options[i],"master_accept_reads") == 0)
|
||||
{
|
||||
router->rwsplit_config.master_reads = config_truth_value(value);
|
||||
}
|
||||
}
|
||||
} /*< for */
|
||||
}
|
||||
@ -4619,7 +4679,7 @@ static void handleError (
|
||||
SESSION* session;
|
||||
ROUTER_INSTANCE* inst = (ROUTER_INSTANCE *)instance;
|
||||
ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES *)router_session;
|
||||
|
||||
|
||||
CHK_DCB(backend_dcb);
|
||||
|
||||
/** Reset error handle flag from a given DCB */
|
||||
@ -4686,14 +4746,15 @@ static void handleError (
|
||||
{
|
||||
/**
|
||||
* This is called in hope of getting replacement for
|
||||
* failed slave(s).
|
||||
* failed slave(s). This call may free rses.
|
||||
*/
|
||||
*succp = handle_error_new_connection(inst,
|
||||
rses,
|
||||
&rses,
|
||||
backend_dcb,
|
||||
errmsgbuf);
|
||||
}
|
||||
rses_end_locked_router_action(rses);
|
||||
/* Free the lock if rses still exists */
|
||||
if (rses) rses_end_locked_router_action(rses);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4762,10 +4823,11 @@ static void handle_error_reply_client(
|
||||
*/
|
||||
static bool handle_error_new_connection(
|
||||
ROUTER_INSTANCE* inst,
|
||||
ROUTER_CLIENT_SES* rses,
|
||||
ROUTER_CLIENT_SES** rses,
|
||||
DCB* backend_dcb,
|
||||
GWBUF* errmsg)
|
||||
{
|
||||
ROUTER_CLIENT_SES* myrses;
|
||||
SESSION* ses;
|
||||
int router_nservers;
|
||||
int max_nslaves;
|
||||
@ -4773,7 +4835,8 @@ static bool handle_error_new_connection(
|
||||
backend_ref_t* bref;
|
||||
bool succp;
|
||||
|
||||
ss_dassert(SPINLOCK_IS_LOCKED(&rses->rses_lock));
|
||||
myrses = *rses;
|
||||
ss_dassert(SPINLOCK_IS_LOCKED(&myrses->rses_lock));
|
||||
|
||||
ses = backend_dcb->session;
|
||||
CHK_SESSION(ses);
|
||||
@ -4781,7 +4844,7 @@ static bool handle_error_new_connection(
|
||||
/**
|
||||
* If bref == NULL it has been replaced already with another one.
|
||||
*/
|
||||
if ((bref = get_bref_from_dcb(rses, backend_dcb)) == NULL)
|
||||
if ((bref = get_bref_from_dcb(myrses, backend_dcb)) == NULL)
|
||||
{
|
||||
succp = true;
|
||||
goto return_succp;
|
||||
@ -4824,25 +4887,25 @@ static bool handle_error_new_connection(
|
||||
(void *)bref);
|
||||
|
||||
router_nservers = router_get_servercount(inst);
|
||||
max_nslaves = rses_get_max_slavecount(rses, router_nservers);
|
||||
max_slave_rlag = rses_get_max_replication_lag(rses);
|
||||
max_nslaves = rses_get_max_slavecount(myrses, router_nservers);
|
||||
max_slave_rlag = rses_get_max_replication_lag(myrses);
|
||||
/**
|
||||
* Try to get replacement slave or at least the minimum
|
||||
* number of slave connections for router session.
|
||||
*/
|
||||
if(inst->rwsplit_config.disable_slave_recovery)
|
||||
{
|
||||
succp = have_enough_servers(&rses,1,router_nservers,inst) ? true : false;
|
||||
succp = have_enough_servers(&myrses,1,router_nservers,inst) ? true : false;
|
||||
}
|
||||
else
|
||||
{
|
||||
succp = select_connect_backend_servers(
|
||||
&rses->rses_master_ref,
|
||||
rses->rses_backend_ref,
|
||||
&myrses->rses_master_ref,
|
||||
myrses->rses_backend_ref,
|
||||
router_nservers,
|
||||
max_nslaves,
|
||||
max_slave_rlag,
|
||||
rses->rses_config.rw_slave_select_criteria,
|
||||
myrses->rses_config.rw_slave_select_criteria,
|
||||
ses,
|
||||
inst);
|
||||
}
|
||||
@ -5079,10 +5142,9 @@ static int router_handle_state_switch(
|
||||
{
|
||||
backend_ref_t* bref;
|
||||
int rc = 1;
|
||||
ROUTER_CLIENT_SES* rses;
|
||||
SESSION* ses;
|
||||
SERVER* srv;
|
||||
|
||||
ROUTER_CLIENT_SES* rses;
|
||||
SESSION* ses;
|
||||
CHK_DCB(dcb);
|
||||
bref = (backend_ref_t *)data;
|
||||
CHK_BACKEND_REF(bref);
|
||||
@ -5103,8 +5165,7 @@ static int router_handle_state_switch(
|
||||
STRSRVSTATUS(srv))));
|
||||
ses = dcb->session;
|
||||
CHK_SESSION(ses);
|
||||
|
||||
rses = (ROUTER_CLIENT_SES *)dcb->session->router_session;
|
||||
rses = (ROUTER_CLIENT_SES *)dcb->session->router_session;
|
||||
CHK_CLIENT_RSES(rses);
|
||||
|
||||
switch (reason) {
|
||||
|
||||
@ -46,7 +46,7 @@ bool extract_database(GWBUF* buf, char* str)
|
||||
tok = strtok_r(query," ;",&saved);
|
||||
if(tok == NULL || strcasecmp(tok,"use") != 0)
|
||||
{
|
||||
skygw_log_write(LOGFILE_ERROR,"Schemarouter: Malformed chage database packet.");
|
||||
skygw_log_write(LOGFILE_ERROR,"extract_database: Malformed chage database packet.");
|
||||
succp = false;
|
||||
goto retblock;
|
||||
}
|
||||
@ -54,7 +54,7 @@ bool extract_database(GWBUF* buf, char* str)
|
||||
tok = strtok_r(NULL," ;",&saved);
|
||||
if(tok == NULL)
|
||||
{
|
||||
skygw_log_write(LOGFILE_ERROR,"Schemarouter: Malformed chage database packet.");
|
||||
skygw_log_write(LOGFILE_ERROR,"extract_database: Malformed chage database packet.");
|
||||
succp = false;
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ parse_mapping_response(ROUTER_CLIENT_SES* rses, char* target, GWBUF* buf)
|
||||
if(PTR_IS_RESULTSET(((unsigned char*)buf->start)) &&
|
||||
modutil_count_signal_packets(buf,0,0,&more) == 2)
|
||||
{
|
||||
ptr = (char*)buf->start;
|
||||
ptr = (unsigned char*)buf->start;
|
||||
|
||||
if(ptr[5] != 1)
|
||||
{
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
#ifndef MAXSCALE_TEST_H
|
||||
#define MAXSCALE_TEST_H
|
||||
#define TEST_DIR "${CMAKE_BINARY_DIR}"
|
||||
#define TEST_LOG_DIR "${CMAKE_BINARY_DIR}/log"
|
||||
#define TEST_BIN_DIR "${CMAKE_BINARY_DIR}/bin"
|
||||
#define TEST_MOD_DIR "${CMAKE_BINARY_DIR}/modules"
|
||||
#define TEST_LIB_DIR "${CMAKE_BINARY_DIR}/lib"
|
||||
#define TEST_ETC_DIR "${CMAKE_BINARY_DIR}/etc"
|
||||
#define TEST_DIR "@CMAKE_BINARY_DIR@"
|
||||
#define TEST_LOG_DIR "@CMAKE_BINARY_DIR@/log"
|
||||
#define TEST_BIN_DIR "@CMAKE_BINARY_DIR@/bin"
|
||||
#define TEST_MOD_DIR "@CMAKE_BINARY_DIR@/modules"
|
||||
#define TEST_LIB_DIR "@CMAKE_BINARY_DIR@/lib"
|
||||
#define TEST_ETC_DIR "@CMAKE_BINARY_DIR@/etc"
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user