Merge branch 'release-1.0GA' into MAX-324
Conflicts: server/MaxScale_template.cnf server/core/service.c
This commit is contained in:
@ -179,7 +179,7 @@ gwbuf_clone(GWBUF *buf)
|
||||
{
|
||||
GWBUF *rval;
|
||||
|
||||
if ((rval = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
|
||||
if ((rval = (GWBUF *)calloc(1,sizeof(GWBUF))) == NULL)
|
||||
{
|
||||
ss_dassert(rval != NULL);
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
@ -194,16 +194,43 @@ GWBUF *rval;
|
||||
rval->start = buf->start;
|
||||
rval->end = buf->end;
|
||||
rval->gwbuf_type = buf->gwbuf_type;
|
||||
rval->properties = NULL;
|
||||
rval->hint = NULL;
|
||||
rval->gwbuf_info = buf->gwbuf_info;
|
||||
rval->gwbuf_bufobj = buf->gwbuf_bufobj;
|
||||
rval->next = NULL;
|
||||
rval->tail = rval;
|
||||
CHK_GWBUF(rval);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone whole GWBUF list instead of single buffer.
|
||||
*
|
||||
* @param buf head of the list to be cloned till the tail of it
|
||||
*
|
||||
* @return head of the cloned list or NULL if the list was empty.
|
||||
*/
|
||||
GWBUF* gwbuf_clone_all(
|
||||
GWBUF* buf)
|
||||
{
|
||||
GWBUF* rval;
|
||||
GWBUF* clonebuf;
|
||||
|
||||
if (buf == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
/** Store the head of the list to rval. */
|
||||
clonebuf = gwbuf_clone(buf);
|
||||
rval = clonebuf;
|
||||
|
||||
while (buf->next)
|
||||
{
|
||||
buf = buf->next;
|
||||
clonebuf->next = gwbuf_clone(buf);
|
||||
clonebuf = clonebuf->next;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
GWBUF *gwbuf_clone_portion(
|
||||
GWBUF *buf,
|
||||
|
@ -1891,7 +1891,7 @@ config_truth_value(char *str)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (strcasecmp(str, "flase") == 0 || strcasecmp(str, "off") == 0)
|
||||
if (strcasecmp(str, "false") == 0 || strcasecmp(str, "off") == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -52,8 +52,32 @@
|
||||
#include <mysqld_error.h>
|
||||
|
||||
|
||||
#define DEFAULT_CONNECT_TIMEOUT 3
|
||||
#define DEFAULT_READ_TIMEOUT 1
|
||||
#define DEFAULT_WRITE_TIMEOUT 2
|
||||
|
||||
#define USERS_QUERY_NO_ROOT " AND user NOT IN ('root')"
|
||||
#define LOAD_MYSQL_USERS_QUERY "SELECT user, host, password, concat(user,host,password,Select_priv) AS userdata, Select_priv AS anydb FROM mysql.user WHERE user IS NOT NULL AND user <> ''"
|
||||
|
||||
#if 0
|
||||
# define LOAD_MYSQL_USERS_QUERY \
|
||||
"SELECT DISTINCT \
|
||||
user.user AS user, \
|
||||
user.host AS host, \
|
||||
user.password AS password, \
|
||||
concat(user.user,user.host,user.password, \
|
||||
IF((user.Select_priv+0)||find_in_set('Select',Coalesce(tp.Table_priv,0)),'Y','N') , \
|
||||
COALESCE( db.db,tp.db, '')) AS userdata, \
|
||||
user.Select_priv AS anydb, \
|
||||
COALESCE( db.db,tp.db, NULL) AS db \
|
||||
FROM \
|
||||
mysql.user LEFT JOIN \
|
||||
mysql.db ON user.user=db.user AND user.host=db.host LEFT JOIN \
|
||||
mysql.tables_priv tp ON user.user=tp.user AND user.host=tp.host \
|
||||
WHERE user.user IS NOT NULL AND user.user <> ''"
|
||||
|
||||
#else
|
||||
# define LOAD_MYSQL_USERS_QUERY "SELECT user, host, password, concat(user,host,password,Select_priv) AS userdata, Select_priv AS anydb FROM mysql.user WHERE user IS NOT NULL AND user <> ''"
|
||||
#endif
|
||||
#define MYSQL_USERS_COUNT "SELECT COUNT(1) AS nusers FROM mysql.user"
|
||||
|
||||
#define MYSQL_USERS_WITH_DB_ORDER " ORDER BY host DESC"
|
||||
@ -85,6 +109,11 @@ void *resource_fetch(HASHTABLE *, char *);
|
||||
int resource_add(HASHTABLE *, char *, char *);
|
||||
int resource_hash(char *);
|
||||
static int normalize_hostname(char *input_host, char *output_host);
|
||||
static int gw_mysql_set_timeouts(
|
||||
MYSQL* handle,
|
||||
int read_timeout,
|
||||
int write_timeout,
|
||||
int connect_timeout);
|
||||
|
||||
/**
|
||||
* Load the user/passwd form mysql.user table into the service users' hashtable
|
||||
@ -219,7 +248,7 @@ HASHTABLE *oldresources;
|
||||
int add_mysql_users_with_host_ipv4(USERS *users, char *user, char *host, char *passwd, char *anydb, char *db) {
|
||||
struct sockaddr_in serv_addr;
|
||||
MYSQL_USER_HOST key;
|
||||
char ret_ip[INET_ADDRSTRLEN + 1]="";
|
||||
char ret_ip[400]="";
|
||||
int ret = 0;
|
||||
|
||||
if (users == NULL || user == NULL || host == NULL) {
|
||||
@ -409,7 +438,8 @@ getDatabases(SERVICE *service, MYSQL *con)
|
||||
*
|
||||
* @param service The current service
|
||||
* @param users The users table into which to load the users
|
||||
* @return -1 on any error or the number of users inserted (0 means no users at all)
|
||||
* @return -1 on any error or the number of users inserted
|
||||
* (0 means no users at all)
|
||||
*/
|
||||
static int
|
||||
getUsers(SERVICE *service, USERS *users)
|
||||
@ -421,20 +451,24 @@ getUsers(SERVICE *service, USERS *users)
|
||||
char *service_passwd = NULL;
|
||||
char *dpwd;
|
||||
int total_users = 0;
|
||||
SERVER *server;
|
||||
SERVER_REF *server;
|
||||
char *users_query;
|
||||
unsigned char hash[SHA_DIGEST_LENGTH]="";
|
||||
char *users_data = NULL;
|
||||
int nusers = 0;
|
||||
int users_data_row_len = MYSQL_USER_MAXLEN + MYSQL_HOST_MAXLEN + MYSQL_PASSWORD_LEN + sizeof(char) + MYSQL_DATABASE_MAXLEN;
|
||||
int users_data_row_len = MYSQL_USER_MAXLEN +
|
||||
MYSQL_HOST_MAXLEN +
|
||||
MYSQL_PASSWORD_LEN +
|
||||
sizeof(char) +
|
||||
MYSQL_DATABASE_MAXLEN;
|
||||
int dbnames = 0;
|
||||
int db_grants = 0;
|
||||
|
||||
serviceGetUser(service, &service_user, &service_passwd);
|
||||
|
||||
if (service_user == NULL || service_passwd == NULL)
|
||||
return -1;
|
||||
|
||||
if (serviceGetUser(service, &service_user, &service_passwd) == 0)
|
||||
{
|
||||
ss_dassert(service_passwd == NULL || service_user == NULL);
|
||||
return -1;
|
||||
}
|
||||
con = mysql_init(NULL);
|
||||
|
||||
if (con == NULL) {
|
||||
@ -444,13 +478,26 @@ getUsers(SERVICE *service, USERS *users)
|
||||
mysql_error(con))));
|
||||
return -1;
|
||||
}
|
||||
/** Set read, write and connect timeout values */
|
||||
if (gw_mysql_set_timeouts(con,
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
DEFAULT_WRITE_TIMEOUT,
|
||||
DEFAULT_CONNECT_TIMEOUT))
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to set timeout values for backend "
|
||||
"connection.")));
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mysql_options(con, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL)) {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to set external connection. "
|
||||
"It is needed for backend server connections. "
|
||||
"Exiting.")));
|
||||
"It is needed for backend server connections.")));
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
@ -458,46 +505,69 @@ getUsers(SERVICE *service, USERS *users)
|
||||
* out of databases
|
||||
* to try
|
||||
*/
|
||||
server = service->databases;
|
||||
server = service->dbref;
|
||||
dpwd = decryptPassword(service_passwd);
|
||||
|
||||
/* Select a server with Master bit, if available */
|
||||
while (server != NULL && !(server->status & SERVER_MASTER)) {
|
||||
server = server->nextdb;
|
||||
while (server != NULL && !(server->server->status & SERVER_MASTER)) {
|
||||
server = server->next;
|
||||
}
|
||||
|
||||
if (service->svc_do_shutdown)
|
||||
{
|
||||
free(dpwd);
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Try loading data from master server */
|
||||
if (server != NULL && (mysql_real_connect(con, server->name, service_user, dpwd, NULL, server->port, NULL, 0) != NULL)) {
|
||||
if (server != NULL &&
|
||||
(mysql_real_connect(con,
|
||||
server->server->name, service_user,
|
||||
dpwd,
|
||||
NULL,
|
||||
server->server->port,
|
||||
NULL, 0) != NULL))
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"Dbusers : Loading data from backend database with Master role [%s:%i] "
|
||||
"for service [%s]",
|
||||
server->name,
|
||||
server->port,
|
||||
"Dbusers : Loading data from backend database with "
|
||||
"Master role [%s:%i] for service [%s]",
|
||||
server->server->name,
|
||||
server->server->port,
|
||||
service->name)));
|
||||
} else {
|
||||
/* load data from other servers via loop */
|
||||
server = service->databases;
|
||||
server = service->dbref;
|
||||
|
||||
while (server != NULL && (mysql_real_connect(con,
|
||||
server->name,
|
||||
service_user,
|
||||
dpwd,
|
||||
NULL,
|
||||
server->port,
|
||||
NULL,
|
||||
0) == NULL))
|
||||
while (!service->svc_do_shutdown &&
|
||||
server != NULL &&
|
||||
(mysql_real_connect(con,
|
||||
server->server->name,
|
||||
service_user,
|
||||
dpwd,
|
||||
NULL,
|
||||
server->server->port,
|
||||
NULL,
|
||||
0) == NULL))
|
||||
{
|
||||
server = server->nextdb;
|
||||
server = server->next;
|
||||
}
|
||||
|
||||
|
||||
if (service->svc_do_shutdown)
|
||||
{
|
||||
free(dpwd);
|
||||
mysql_close(con);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (server != NULL) {
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"Dbusers : Loading data from backend database [%s:%i] "
|
||||
"for service [%s]",
|
||||
server->name,
|
||||
server->port,
|
||||
"Dbusers : Loading data from backend database "
|
||||
"[%s:%i] for service [%s]",
|
||||
server->server->name,
|
||||
server->server->port,
|
||||
service->name)));
|
||||
}
|
||||
}
|
||||
@ -515,9 +585,7 @@ getUsers(SERVICE *service, USERS *users)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* count users */
|
||||
|
||||
/* start with users and db grants for users */
|
||||
/** Count users. Start with users and db grants for users */
|
||||
if (mysql_query(con, MYSQL_USERS_WITH_DB_COUNT)) {
|
||||
if (mysql_errno(con) != ER_TABLEACCESS_DENIED_ERROR) {
|
||||
/* This is an error we cannot handle, return */
|
||||
@ -1193,3 +1261,58 @@ int useorig = 0;
|
||||
|
||||
return netmask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set read, write and connect timeout values for MySQL database connection.
|
||||
*
|
||||
* @param handle MySQL handle
|
||||
* @param read_timeout Read timeout value in seconds
|
||||
* @param write_timeout Write timeout value in seconds
|
||||
* @param connect_timeout Connect timeout value in seconds
|
||||
*
|
||||
* @return 0 if succeed, 1 if failed
|
||||
*/
|
||||
static int gw_mysql_set_timeouts(
|
||||
MYSQL* handle,
|
||||
int read_timeout,
|
||||
int write_timeout,
|
||||
int connect_timeout)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = mysql_options(handle,
|
||||
MYSQL_OPT_READ_TIMEOUT,
|
||||
(void *)&read_timeout)))
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to set read timeout for backend "
|
||||
"connection.")));
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
if ((rc = mysql_options(handle,
|
||||
MYSQL_OPT_CONNECT_TIMEOUT,
|
||||
(void *)&connect_timeout)))
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to set connect timeout for backend "
|
||||
"connection.")));
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
if ((rc = mysql_options(handle,
|
||||
MYSQL_OPT_WRITE_TIMEOUT,
|
||||
(void *)&write_timeout)))
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to set write timeout for backend "
|
||||
"connection.")));
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
retblock:
|
||||
return rc;
|
||||
}
|
@ -190,7 +190,7 @@ DCB *rval;
|
||||
rval->readcheck = 0;
|
||||
rval->polloutbusy = 0;
|
||||
rval->writecheck = 0;
|
||||
rval->fd = -1;
|
||||
rval->fd = DCBFD_CLOSED;
|
||||
|
||||
rval->evq.next = NULL;
|
||||
rval->evq.prev = NULL;
|
||||
@ -235,8 +235,10 @@ DCB *rval;
|
||||
void
|
||||
dcb_free(DCB *dcb)
|
||||
{
|
||||
if (dcb->fd == -1)
|
||||
if (dcb->fd == DCBFD_CLOSED)
|
||||
{
|
||||
dcb_final_free(dcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
@ -308,7 +310,7 @@ DCB *clone;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
clone->fd = -1;
|
||||
clone->fd = DCBFD_CLOSED;
|
||||
clone->flags |= DCBF_CLONE;
|
||||
clone->state = orig->state;
|
||||
clone->data = orig->data;
|
||||
@ -319,7 +321,10 @@ DCB *clone;
|
||||
clone->protocol = orig->protocol;
|
||||
|
||||
clone->func.write = dcb_null_write;
|
||||
clone->func.close = dcb_null_close;
|
||||
/**
|
||||
* Close triggers closing of router session as well which is needed.
|
||||
*/
|
||||
clone->func.close = orig->func.close;
|
||||
clone->func.auth = dcb_null_auth;
|
||||
|
||||
return clone;
|
||||
@ -383,22 +388,25 @@ DCB_CALLBACK *cb;
|
||||
*/
|
||||
{
|
||||
SESSION *local_session = dcb->session;
|
||||
dcb->session = NULL;
|
||||
CHK_SESSION(local_session);
|
||||
/*<
|
||||
* Remove reference from session if dcb is client.
|
||||
*/
|
||||
if (local_session->client == dcb) {
|
||||
local_session->client = NULL;
|
||||
}
|
||||
dcb->session = NULL;
|
||||
/**
|
||||
* Set session's client pointer NULL so that other threads
|
||||
* won't try to call dcb_close for client DCB
|
||||
* after this call.
|
||||
*/
|
||||
if (local_session->client == dcb)
|
||||
{
|
||||
spinlock_acquire(&local_session->ses_lock);
|
||||
local_session->client = NULL;
|
||||
spinlock_release(&local_session->ses_lock);
|
||||
}
|
||||
session_free(local_session);
|
||||
}
|
||||
}
|
||||
|
||||
if (dcb->protocol && ((dcb->flags & DCBF_CLONE) ==0))
|
||||
free(dcb->protocol);
|
||||
if (dcb->data && ((dcb->flags & DCBF_CLONE) ==0))
|
||||
free(dcb->data);
|
||||
if (dcb->protocol && (!DCB_IS_CLONE(dcb)))
|
||||
free(dcb->protocol);
|
||||
if (dcb->remote)
|
||||
free(dcb->remote);
|
||||
if (dcb->user)
|
||||
@ -423,7 +431,6 @@ DCB_CALLBACK *cb;
|
||||
}
|
||||
spinlock_release(&dcb->cb_lock);
|
||||
|
||||
|
||||
bitmask_free(&dcb->memdata.bitmask);
|
||||
free(dcb);
|
||||
}
|
||||
@ -551,40 +558,42 @@ bool succp = false;
|
||||
DCB* dcb_next = NULL;
|
||||
int rc = 0;
|
||||
|
||||
/*<
|
||||
* Close file descriptor and move to clean-up phase.
|
||||
*/
|
||||
rc = close(dcb->fd);
|
||||
if (dcb->fd > 0)
|
||||
{
|
||||
/*<
|
||||
* Close file descriptor and move to clean-up phase.
|
||||
*/
|
||||
rc = close(dcb->fd);
|
||||
|
||||
if (rc < 0) {
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Failed to close "
|
||||
"socket %d on dcb %p due error %d, %s.",
|
||||
dcb->fd,
|
||||
dcb,
|
||||
eno,
|
||||
strerror(eno))));
|
||||
}
|
||||
#if defined(SS_DEBUG)
|
||||
else {
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_process_zombies] Closed socket "
|
||||
"%d on dcb %p.",
|
||||
pthread_self(),
|
||||
dcb->fd,
|
||||
dcb)));
|
||||
#endif /* SS_DEBUG */
|
||||
if (rc < 0)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Failed to close "
|
||||
"socket %d on dcb %p due error %d, %s.",
|
||||
dcb->fd,
|
||||
dcb,
|
||||
eno,
|
||||
strerror(eno))));
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb->fd = DCBFD_CLOSED;
|
||||
|
||||
LOGIF(LD, (skygw_log_write_flush(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_process_zombies] Closed socket "
|
||||
"%d on dcb %p.",
|
||||
pthread_self(),
|
||||
dcb->fd,
|
||||
dcb)));
|
||||
#if defined(FAKE_CODE)
|
||||
conn_open[dcb->fd] = false;
|
||||
conn_open[dcb->fd] = false;
|
||||
#endif /* FAKE_CODE */
|
||||
#if defined(SS_DEBUG)
|
||||
ss_debug(dcb->fd = -1;)
|
||||
}
|
||||
#endif /* SS_DEBUG */
|
||||
}
|
||||
}
|
||||
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
|
||||
dcb,
|
||||
&tls_log_info.li_sesid,
|
||||
@ -657,7 +666,7 @@ int rc;
|
||||
}
|
||||
fd = dcb->func.connect(dcb, server, session);
|
||||
|
||||
if (fd == -1) {
|
||||
if (fd == DCBFD_CLOSED) {
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
"%lu [dcb_connect] Failed to connect to server %s:%d, "
|
||||
@ -683,7 +692,7 @@ int rc;
|
||||
session->client,
|
||||
session->client->fd)));
|
||||
}
|
||||
ss_dassert(dcb->fd == -1); /*< must be uninitialized at this point */
|
||||
ss_dassert(dcb->fd == DCBFD_CLOSED); /*< must be uninitialized at this point */
|
||||
/*<
|
||||
* Successfully connected to backend. Assign file descriptor to dcb
|
||||
*/
|
||||
@ -704,7 +713,7 @@ int rc;
|
||||
*/
|
||||
rc = poll_add_dcb(dcb);
|
||||
|
||||
if (rc == -1) {
|
||||
if (rc == DCBFD_CLOSED) {
|
||||
dcb_set_state(dcb, DCB_STATE_DISCONNECTED, NULL);
|
||||
dcb_final_free(dcb);
|
||||
return NULL;
|
||||
@ -736,11 +745,22 @@ int dcb_read(
|
||||
GWBUF *buffer = NULL;
|
||||
int b;
|
||||
int rc;
|
||||
int n ;
|
||||
int n;
|
||||
int nread = 0;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
while (true)
|
||||
|
||||
if (dcb->fd <= 0)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Read failed, dcb is %s.",
|
||||
dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not readable")));
|
||||
n = 0;
|
||||
goto return_n;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
int bufsize;
|
||||
|
||||
@ -864,6 +884,14 @@ int below_water;
|
||||
below_water = (dcb->high_water && dcb->writeqlen < dcb->high_water) ? 1 : 0;
|
||||
ss_dassert(queue != NULL);
|
||||
|
||||
if (dcb->fd <= 0)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Write failed, dcb is %s.",
|
||||
dcb->fd == DCBFD_CLOSED ? "closed" : "cloned, not writable")));
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* SESSION_STATE_STOPPING means that one of the backends is closing
|
||||
* the router session. Some backends may have not completed
|
||||
@ -877,7 +905,8 @@ int below_water;
|
||||
dcb->state != DCB_STATE_POLLING &&
|
||||
dcb->state != DCB_STATE_LISTENING &&
|
||||
dcb->state != DCB_STATE_NOPOLLING &&
|
||||
dcb->session->state != SESSION_STATE_STOPPING))
|
||||
(dcb->session == NULL ||
|
||||
dcb->session->state != SESSION_STATE_STOPPING)))
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
@ -888,7 +917,7 @@ int below_water;
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd)));
|
||||
ss_dassert(false);
|
||||
//ss_dassert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1209,46 +1238,42 @@ dcb_close(DCB *dcb)
|
||||
*/
|
||||
if (dcb->state == DCB_STATE_POLLING)
|
||||
{
|
||||
if (dcb->fd != -1)
|
||||
{
|
||||
rc = poll_remove_dcb(dcb);
|
||||
rc = poll_remove_dcb(dcb);
|
||||
|
||||
if (rc == 0) {
|
||||
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))));
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Removing DCB fd == %d in state %s from "
|
||||
"poll set failed.",
|
||||
dcb->fd,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
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))));
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Removing DCB fd == %d in state %s from "
|
||||
"poll set failed.",
|
||||
dcb->fd,
|
||||
STRDCBSTATE(dcb->state))));
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
/**
|
||||
* close protocol and router session
|
||||
*/
|
||||
if (dcb->func.close != NULL)
|
||||
{
|
||||
/**
|
||||
* close protocol and router session
|
||||
*/
|
||||
if (dcb->func.close != NULL)
|
||||
{
|
||||
dcb->func.close(dcb);
|
||||
}
|
||||
dcb_call_callback(dcb, DCB_REASON_CLOSE);
|
||||
|
||||
|
||||
if (dcb->state == DCB_STATE_NOPOLLING)
|
||||
{
|
||||
dcb_add_to_zombieslist(dcb);
|
||||
}
|
||||
dcb->func.close(dcb);
|
||||
}
|
||||
/** Call possible callback for this DCB in case of close */
|
||||
dcb_call_callback(dcb, DCB_REASON_CLOSE);
|
||||
|
||||
if (dcb->state == DCB_STATE_NOPOLLING)
|
||||
{
|
||||
dcb_add_to_zombieslist(dcb);
|
||||
}
|
||||
}
|
||||
|
||||
ss_dassert(dcb->state == DCB_STATE_NOPOLLING ||
|
||||
dcb->state == DCB_STATE_ZOMBIE);
|
||||
}
|
||||
@ -1585,7 +1610,9 @@ void dcb_hashtable_stats(
|
||||
hashsize);
|
||||
|
||||
dcb_printf(dcb, "\tNo. of entries: %d\n", total);
|
||||
dcb_printf(dcb, "\tAverage chain length: %.1f\n", (float)total / hashsize);
|
||||
dcb_printf(dcb,
|
||||
"\tAverage chain length: %.1f\n",
|
||||
(hashsize == 0 ? (float)hashsize : (float)total / hashsize));
|
||||
dcb_printf(dcb, "\tLongest chain length: %d\n", longest);
|
||||
}
|
||||
|
||||
@ -1757,14 +1784,16 @@ static bool dcb_set_state_nomutex(
|
||||
* @param dcb The DCB to write buffer
|
||||
* @param buf Buffer to write
|
||||
* @param nbytes Number of bytes to write
|
||||
* @return Number of written bytes
|
||||
*/
|
||||
int
|
||||
gw_write(DCB *dcb, const void *buf, size_t nbytes)
|
||||
{
|
||||
int w;
|
||||
int w = 0;
|
||||
int fd = dcb->fd;
|
||||
#if defined(FAKE_CODE)
|
||||
if (dcb_fake_write_errno[fd] != 0) {
|
||||
if (fd > 0 && dcb_fake_write_errno[fd] != 0)
|
||||
{
|
||||
ss_dassert(dcb_fake_write_ev[fd] != 0);
|
||||
w = write(fd, buf, nbytes/2); /*< leave peer to read missing bytes */
|
||||
|
||||
@ -1772,11 +1801,15 @@ gw_write(DCB *dcb, const void *buf, size_t nbytes)
|
||||
w = -1;
|
||||
errno = dcb_fake_write_errno[fd];
|
||||
}
|
||||
} else {
|
||||
} else if (fd > 0)
|
||||
{
|
||||
w = write(fd, buf, nbytes);
|
||||
}
|
||||
#else
|
||||
w = write(fd, buf, nbytes);
|
||||
if (fd > 0)
|
||||
{
|
||||
w = write(fd, buf, nbytes);
|
||||
}
|
||||
#endif /* FAKE_CODE */
|
||||
|
||||
#if defined(SS_DEBUG_MYSQL)
|
||||
@ -1958,6 +1991,12 @@ DCB_CALLBACK *cb, *nextcb;
|
||||
{
|
||||
nextcb = cb->next;
|
||||
spinlock_release(&dcb->cb_lock);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG,
|
||||
"%lu [dcb_call_callback] %s",
|
||||
pthread_self(),
|
||||
STRDCBREASON(reason))));
|
||||
|
||||
cb->cb(dcb, reason, cb->userdata);
|
||||
spinlock_acquire(&dcb->cb_lock);
|
||||
cb = nextcb;
|
||||
@ -2043,6 +2082,10 @@ dcb_get_next (DCB* dcb)
|
||||
void
|
||||
dcb_call_foreach(DCB_REASON reason)
|
||||
{
|
||||
LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG,
|
||||
"%lu [dcb_call_foreach]",
|
||||
pthread_self())));
|
||||
|
||||
switch (reason) {
|
||||
case DCB_REASON_CLOSE:
|
||||
case DCB_REASON_DRAINED:
|
||||
@ -2075,7 +2118,7 @@ dcb_call_foreach(DCB_REASON reason)
|
||||
|
||||
/**
|
||||
* Null protocol write routine used for cloned dcb's. It merely consumes
|
||||
* buffers written on the cloned DCB.
|
||||
* buffers written on the cloned DCB and sets the DCB_REPLIED flag.
|
||||
*
|
||||
* @param dcb The descriptor control block
|
||||
* @param buf The buffer being written
|
||||
@ -2088,6 +2131,9 @@ dcb_null_write(DCB *dcb, GWBUF *buf)
|
||||
{
|
||||
buf = gwbuf_consume(buf, GWBUF_LENGTH(buf));
|
||||
}
|
||||
|
||||
dcb->flags |= DCBF_REPLIED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -91,28 +91,31 @@ filter_free(FILTER_DEF *filter)
|
||||
{
|
||||
FILTER_DEF *ptr;
|
||||
|
||||
/* First of all remove from the linked list */
|
||||
spinlock_acquire(&filter_spin);
|
||||
if (allFilters == filter)
|
||||
if (filter)
|
||||
{
|
||||
allFilters = filter->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = allFilters;
|
||||
while (ptr && ptr->next != filter)
|
||||
/* First of all remove from the linked list */
|
||||
spinlock_acquire(&filter_spin);
|
||||
if (allFilters == filter)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
allFilters = filter->next;
|
||||
}
|
||||
if (ptr)
|
||||
ptr->next = filter->next;
|
||||
}
|
||||
spinlock_release(&filter_spin);
|
||||
else
|
||||
{
|
||||
ptr = allFilters;
|
||||
while (ptr && ptr->next != filter)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
}
|
||||
if (ptr)
|
||||
ptr->next = filter->next;
|
||||
}
|
||||
spinlock_release(&filter_spin);
|
||||
|
||||
/* Clean up session and free the memory */
|
||||
free(filter->name);
|
||||
free(filter->module);
|
||||
free(filter);
|
||||
/* Clean up session and free the memory */
|
||||
free(filter->name);
|
||||
free(filter->module);
|
||||
free(filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include <config.h>
|
||||
#include <poll.h>
|
||||
#include <housekeeper.h>
|
||||
#include <service.h>
|
||||
#include <memlog.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -572,7 +573,7 @@ return_succp:
|
||||
static bool resolve_maxscale_homedir(
|
||||
char** p_home_dir)
|
||||
{
|
||||
bool succp;
|
||||
bool succp = false;
|
||||
char* tmp;
|
||||
char* tmp2;
|
||||
char* log_context = NULL;
|
||||
@ -1837,7 +1838,8 @@ return_main:
|
||||
void
|
||||
shutdown_server()
|
||||
{
|
||||
poll_shutdown();
|
||||
service_shutdown();
|
||||
poll_shutdown();
|
||||
hkshutdown();
|
||||
memlog_flush_all();
|
||||
log_flush_shutdown();
|
||||
|
@ -81,7 +81,7 @@ setipaddress(struct in_addr *a, char *p) {
|
||||
if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0) {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : getaddrinfo failed for [%s] due [%s]",
|
||||
"Error: Failed to obtain address for host %s, %s",
|
||||
p,
|
||||
gai_strerror(rc))));
|
||||
|
||||
@ -94,7 +94,7 @@ setipaddress(struct in_addr *a, char *p) {
|
||||
if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0) {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : getaddrinfo failed for [%s] due [%s]",
|
||||
"Error: Failed to obtain address for host %s, %s",
|
||||
p,
|
||||
gai_strerror(rc))));
|
||||
|
||||
|
@ -449,28 +449,33 @@ void hashtable_get_stats(
|
||||
int i;
|
||||
int j;
|
||||
|
||||
ht = (HASHTABLE *)table;
|
||||
CHK_HASHTABLE(ht);
|
||||
*nelems = 0;
|
||||
*longest = 0;
|
||||
hashtable_read_lock(ht);
|
||||
|
||||
for (i = 0; i < ht->hashsize; i++)
|
||||
*nelems = 0;
|
||||
*longest = 0;
|
||||
*hashsize = 0;
|
||||
|
||||
if (table != NULL)
|
||||
{
|
||||
j = 0;
|
||||
entries = ht->entries[i];
|
||||
while (entries)
|
||||
ht = (HASHTABLE *)table;
|
||||
CHK_HASHTABLE(ht);
|
||||
hashtable_read_lock(ht);
|
||||
|
||||
for (i = 0; i < ht->hashsize; i++)
|
||||
{
|
||||
j++;
|
||||
entries = entries->next;
|
||||
j = 0;
|
||||
entries = ht->entries[i];
|
||||
while (entries)
|
||||
{
|
||||
j++;
|
||||
entries = entries->next;
|
||||
}
|
||||
*nelems += j;
|
||||
if (j > *longest) {
|
||||
*longest = j;
|
||||
}
|
||||
}
|
||||
*nelems += j;
|
||||
if (j > *longest) {
|
||||
*longest = j;
|
||||
}
|
||||
*hashsize = ht->hashsize;
|
||||
hashtable_read_unlock(ht);
|
||||
}
|
||||
*hashsize = ht->hashsize;
|
||||
hashtable_read_unlock(ht);
|
||||
}
|
||||
|
||||
|
||||
@ -503,7 +508,7 @@ hashtable_read_lock(HASHTABLE *table)
|
||||
;
|
||||
spinlock_acquire(&table->spin);
|
||||
}
|
||||
table->n_readers++;
|
||||
atomic_add(&table->n_readers, 1);
|
||||
spinlock_release(&table->spin);
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,40 @@ unsigned char *ptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the length of MySQL packet and how much is missing from the GWBUF
|
||||
* passed as parameter.
|
||||
*
|
||||
* This routine assumes that there is only one MySQL packet in the buffer.
|
||||
*
|
||||
* @param buf buffer list including the query, may consist of
|
||||
* multiple buffers
|
||||
* @param nbytes_missing pointer to missing bytecount
|
||||
*
|
||||
* @return the length of MySQL packet and writes missing bytecount to
|
||||
* nbytes_missing.
|
||||
*/
|
||||
int modutil_MySQL_query_len(
|
||||
GWBUF* buf,
|
||||
int* nbytes_missing)
|
||||
{
|
||||
int len;
|
||||
int buflen;
|
||||
|
||||
if (!modutil_is_SQL(buf))
|
||||
{
|
||||
len = 0;
|
||||
goto retblock;
|
||||
}
|
||||
len = MYSQL_GET_PACKET_LEN((uint8_t *)GWBUF_DATA(buf));
|
||||
*nbytes_missing = len-1;
|
||||
buflen = gwbuf_length(buf);
|
||||
|
||||
*nbytes_missing -= buflen-5;
|
||||
|
||||
retblock:
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -178,7 +212,7 @@ GWBUF *addition;
|
||||
|
||||
/**
|
||||
* Extract the SQL from a COM_QUERY packet and return in a NULL terminated buffer.
|
||||
* The buffer shoudl be freed by the caller when it is no longer required.
|
||||
* The buffer should be freed by the caller when it is no longer required.
|
||||
*
|
||||
* If the packet is not a COM_QUERY packet then the function will return NULL
|
||||
*
|
||||
@ -234,7 +268,7 @@ modutil_get_query(GWBUF *buf)
|
||||
uint8_t* packet;
|
||||
mysql_server_cmd_t packet_type;
|
||||
size_t len;
|
||||
char* query_str;
|
||||
char* query_str = NULL;
|
||||
|
||||
packet = GWBUF_DATA(buf);
|
||||
packet_type = packet[4];
|
||||
@ -252,7 +286,7 @@ modutil_get_query(GWBUF *buf)
|
||||
|
||||
case MYSQL_COM_QUERY:
|
||||
len = MYSQL_GET_PACKET_LEN(packet)-1; /*< distract 1 for packet type byte */
|
||||
if ((query_str = (char *)malloc(len+1)) == NULL)
|
||||
if (len < 1 || len > ~(size_t)0 - 1 || (query_str = (char *)malloc(len+1)) == NULL)
|
||||
{
|
||||
goto retblock;
|
||||
}
|
||||
@ -262,7 +296,7 @@ modutil_get_query(GWBUF *buf)
|
||||
|
||||
default:
|
||||
len = strlen(STRPACKETTYPE(packet_type))+1;
|
||||
if ((query_str = (char *)malloc(len+1)) == NULL)
|
||||
if (len < 1 || len > ~(size_t)0 - 1 || (query_str = (char *)malloc(len+1)) == NULL)
|
||||
{
|
||||
goto retblock;
|
||||
}
|
||||
@ -390,3 +424,72 @@ int modutil_send_mysql_err_packet (
|
||||
return dcb->func.write(dcb, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer contains at least one of the following:
|
||||
* complete [complete] [partial] mysql packet
|
||||
*
|
||||
* return pointer to gwbuf containing a complete packet or
|
||||
* NULL if no complete packet was found.
|
||||
*/
|
||||
GWBUF* modutil_get_next_MySQL_packet(
|
||||
GWBUF** p_readbuf)
|
||||
{
|
||||
GWBUF* packetbuf;
|
||||
GWBUF* readbuf;
|
||||
size_t buflen;
|
||||
size_t packetlen;
|
||||
size_t totalbuflen;
|
||||
uint8_t* data;
|
||||
size_t nbytes_copied = 0;
|
||||
uint8_t* target;
|
||||
|
||||
readbuf = *p_readbuf;
|
||||
|
||||
if (readbuf == NULL)
|
||||
{
|
||||
packetbuf = NULL;
|
||||
goto return_packetbuf;
|
||||
}
|
||||
CHK_GWBUF(readbuf);
|
||||
|
||||
if (GWBUF_EMPTY(readbuf))
|
||||
{
|
||||
packetbuf = NULL;
|
||||
goto return_packetbuf;
|
||||
}
|
||||
totalbuflen = gwbuf_length(readbuf);
|
||||
data = (uint8_t *)GWBUF_DATA((readbuf));
|
||||
packetlen = MYSQL_GET_PACKET_LEN(data)+4;
|
||||
|
||||
/** packet is incomplete */
|
||||
if (packetlen > totalbuflen)
|
||||
{
|
||||
packetbuf = NULL;
|
||||
goto return_packetbuf;
|
||||
}
|
||||
|
||||
packetbuf = gwbuf_alloc(packetlen);
|
||||
target = GWBUF_DATA(packetbuf);
|
||||
packetbuf->gwbuf_type = readbuf->gwbuf_type; /*< Copy the type too */
|
||||
/**
|
||||
* Copy first MySQL packet to packetbuf and leave posible other
|
||||
* packets to read buffer.
|
||||
*/
|
||||
while (nbytes_copied < packetlen && totalbuflen > 0)
|
||||
{
|
||||
uint8_t* src = GWBUF_DATA((*p_readbuf));
|
||||
size_t bytestocopy;
|
||||
|
||||
buflen = GWBUF_LENGTH((*p_readbuf));
|
||||
bytestocopy = MIN(buflen,packetlen-nbytes_copied);
|
||||
|
||||
memcpy(target+nbytes_copied, src, bytestocopy);
|
||||
*p_readbuf = gwbuf_consume((*p_readbuf), bytestocopy);
|
||||
totalbuflen = gwbuf_length((*p_readbuf));
|
||||
nbytes_copied += bytestocopy;
|
||||
}
|
||||
ss_dassert(buflen == 0 || nbytes_copied == packetlen);
|
||||
|
||||
return_packetbuf:
|
||||
return packetbuf;
|
||||
}
|
||||
|
@ -341,19 +341,26 @@ poll_remove_dcb(DCB *dcb)
|
||||
/*<
|
||||
* Set state to NOPOLLING and remove dcb from poll set.
|
||||
*/
|
||||
if (dcb_set_state(dcb, new_state, &old_state)) {
|
||||
rc = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dcb->fd, &ev);
|
||||
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 */
|
||||
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.
|
||||
@ -1323,7 +1330,6 @@ void poll_add_epollin_event_to_dcb(
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void poll_add_event_to_dcb(
|
||||
DCB* dcb,
|
||||
GWBUF* buf,
|
||||
|
@ -252,6 +252,7 @@ MAXKEYS key;
|
||||
"Error : failed opening /dev/random. Error %d, %s.",
|
||||
errno,
|
||||
strerror(errno))));
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -260,6 +261,7 @@ MAXKEYS key;
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : failed to read /dev/random.")));
|
||||
close(fd);
|
||||
close(randfd);
|
||||
return 1;
|
||||
}
|
||||
|
@ -68,25 +68,16 @@ server_alloc(char *servname, char *protocol, unsigned short port)
|
||||
{
|
||||
SERVER *server;
|
||||
|
||||
if ((server = (SERVER *)malloc(sizeof(SERVER))) == NULL)
|
||||
if ((server = (SERVER *)calloc(1, sizeof(SERVER))) == NULL)
|
||||
return NULL;
|
||||
server->name = strdup(servname);
|
||||
server->protocol = strdup(protocol);
|
||||
server->port = port;
|
||||
memset(&server->stats, 0, sizeof(SERVER_STATS));
|
||||
server->status = SERVER_RUNNING;
|
||||
server->nextdb = NULL;
|
||||
server->monuser = NULL;
|
||||
server->monpw = NULL;
|
||||
server->unique_name = NULL;
|
||||
server->server_string = NULL;
|
||||
server->node_id = -1;
|
||||
server->rlag = -2;
|
||||
server->node_ts = 0;
|
||||
server->parameters = NULL;
|
||||
server->master_id = -1;
|
||||
server->depth = -1;
|
||||
server->slaves = NULL;
|
||||
|
||||
spinlock_acquire(&server_spin);
|
||||
server->next = allServers;
|
||||
@ -451,6 +442,12 @@ void
|
||||
server_set_status(SERVER *server, int bit)
|
||||
{
|
||||
server->status |= bit;
|
||||
|
||||
/** clear error logged flag before the next failure */
|
||||
if (SERVER_IS_MASTER(server))
|
||||
{
|
||||
server->master_err_is_logged = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,7 +87,6 @@ static void service_add_qualified_param(
|
||||
SERVICE* svc,
|
||||
CONFIG_PARAMETER* param);
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a new service for the gateway to support
|
||||
*
|
||||
@ -102,7 +101,7 @@ service_alloc(const char *servname, const char *router)
|
||||
{
|
||||
SERVICE *service;
|
||||
|
||||
if ((service = (SERVICE *)malloc(sizeof(SERVICE))) == NULL)
|
||||
if ((service = (SERVICE *)calloc(1, sizeof(SERVICE))) == NULL)
|
||||
return NULL;
|
||||
if ((service->router = load_module(router, MODULE_ROUTER)) == NULL)
|
||||
{
|
||||
@ -132,27 +131,10 @@ SERVICE *service;
|
||||
free(service);
|
||||
return NULL;
|
||||
}
|
||||
service->version_string = NULL;
|
||||
memset(&service->stats, 0, sizeof(SERVICE_STATS));
|
||||
service->ports = NULL;
|
||||
service->stats.started = time(0);
|
||||
service->state = SERVICE_STATE_ALLOC;
|
||||
service->credentials.name = NULL;
|
||||
service->credentials.authdata = NULL;
|
||||
service->enable_root = 0;
|
||||
service->localhost_match_wildcard_host = 0;
|
||||
service->routerOptions = NULL;
|
||||
service->databases = NULL;
|
||||
service->svc_config_param = NULL;
|
||||
service->svc_config_version = 0;
|
||||
service->filters = NULL;
|
||||
service->n_filters = 0;
|
||||
service->weightby = 0;
|
||||
service->users = NULL;
|
||||
service->resources = NULL;
|
||||
spinlock_init(&service->spin);
|
||||
spinlock_init(&service->users_table_spin);
|
||||
memset(&service->rate_limit, 0, sizeof(SERVICE_REFRESH_RATE));
|
||||
|
||||
spinlock_acquire(&service_spin);
|
||||
service->next = allServices;
|
||||
@ -233,11 +215,6 @@ GWPROTOCOL *funcs;
|
||||
(port->address == NULL ? "0.0.0.0" : port->address),
|
||||
port->port,
|
||||
service->name)));
|
||||
hashtable_free(service->users->data);
|
||||
free(service->users);
|
||||
dcb_free(port->listener);
|
||||
port->listener = NULL;
|
||||
goto retblock;
|
||||
}
|
||||
/* At service start last update is set to USERS_REFRESH_TIME seconds earlier.
|
||||
* This way MaxScale could try reloading users' just after startup
|
||||
@ -349,28 +326,28 @@ serviceStart(SERVICE *service)
|
||||
SERV_PROTOCOL *port;
|
||||
int listeners = 0;
|
||||
|
||||
service->router_instance = service->router->createInstance(service,
|
||||
service->routerOptions);
|
||||
if ((service->router_instance = service->router->createInstance(service,
|
||||
service->routerOptions)) == NULL)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"%s: Failed to create router instance for service. Service not started.",
|
||||
service->name)));
|
||||
service->state = SERVICE_STATE_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (service->router_instance == NULL)
|
||||
port = service->ports;
|
||||
while (!service->svc_do_shutdown && port)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : starting the %s service failed.",
|
||||
service->name)));
|
||||
|
||||
listeners += serviceStartPort(service, port);
|
||||
port = port->next;
|
||||
}
|
||||
else
|
||||
if (listeners)
|
||||
{
|
||||
port = service->ports;
|
||||
while (port)
|
||||
{
|
||||
listeners += serviceStartPort(service, port);
|
||||
port = port->next;
|
||||
}
|
||||
if (listeners)
|
||||
service->stats.started = time(0);
|
||||
service->state = SERVICE_STATE_STARTED;
|
||||
service->stats.started = time(0);
|
||||
}
|
||||
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@ -405,12 +382,21 @@ int
|
||||
serviceStartAll()
|
||||
{
|
||||
SERVICE *ptr;
|
||||
int n = 0;
|
||||
int n = 0,i;
|
||||
|
||||
ptr = allServices;
|
||||
while (ptr)
|
||||
while (ptr && !ptr->svc_do_shutdown)
|
||||
{
|
||||
n += serviceStart(ptr);
|
||||
n += (i = serviceStart(ptr));
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write(
|
||||
LOGFILE_ERROR,
|
||||
"Error : Failed to start service '%s'.",
|
||||
ptr->name)));
|
||||
}
|
||||
|
||||
ptr = ptr->next;
|
||||
}
|
||||
return n;
|
||||
@ -439,6 +425,7 @@ int listeners = 0;
|
||||
|
||||
port = port->next;
|
||||
}
|
||||
service->state = SERVICE_STATE_STOPPED;
|
||||
|
||||
return listeners;
|
||||
}
|
||||
@ -481,7 +468,7 @@ int
|
||||
service_free(SERVICE *service)
|
||||
{
|
||||
SERVICE *ptr;
|
||||
|
||||
SERVER_REF *srv;
|
||||
if (service->stats.n_current)
|
||||
return 0;
|
||||
/* First of all remove from the linked list */
|
||||
@ -503,6 +490,13 @@ SERVICE *ptr;
|
||||
spinlock_release(&service_spin);
|
||||
|
||||
/* Clean up session and free the memory */
|
||||
|
||||
while(service->dbref){
|
||||
srv = service->dbref;
|
||||
service->dbref = service->dbref->next;
|
||||
free(srv);
|
||||
}
|
||||
|
||||
free(service->name);
|
||||
free(service->routerModule);
|
||||
if (service->credentials.name)
|
||||
@ -581,8 +575,13 @@ void
|
||||
serviceAddBackend(SERVICE *service, SERVER *server)
|
||||
{
|
||||
spinlock_acquire(&service->spin);
|
||||
server->nextdb = service->databases;
|
||||
service->databases = server;
|
||||
SERVER_REF *sref;
|
||||
if((sref = calloc(1,sizeof(SERVER_REF))) != NULL)
|
||||
{
|
||||
sref->next = service->dbref;
|
||||
sref->server = server;
|
||||
service->dbref = sref;
|
||||
}
|
||||
spinlock_release(&service->spin);
|
||||
}
|
||||
|
||||
@ -596,12 +595,12 @@ serviceAddBackend(SERVICE *service, SERVER *server)
|
||||
int
|
||||
serviceHasBackend(SERVICE *service, SERVER *server)
|
||||
{
|
||||
SERVER *ptr;
|
||||
SERVER_REF *ptr;
|
||||
|
||||
spinlock_acquire(&service->spin);
|
||||
ptr = service->databases;
|
||||
while (ptr && ptr != server)
|
||||
ptr = ptr->nextdb;
|
||||
ptr = service->dbref;
|
||||
while (ptr && ptr->server != server)
|
||||
ptr = ptr->next;
|
||||
spinlock_release(&service->spin);
|
||||
|
||||
return ptr != NULL;
|
||||
@ -759,7 +758,7 @@ int n = 0;
|
||||
if ((flist = (FILTER_DEF **)malloc(sizeof(FILTER_DEF *))) == NULL)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Out of memory adding filters to service.\n")));
|
||||
"Error : Out of memory adding filters to service.\n")));
|
||||
return;
|
||||
}
|
||||
ptr = strtok_r(filters, "|", &brkt);
|
||||
@ -770,14 +769,14 @@ int n = 0;
|
||||
(n + 1) * sizeof(FILTER_DEF *))) == NULL)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
|
||||
"Out of memory adding filters to service.\n")));
|
||||
"Error : Out of memory adding filters to service.\n")));
|
||||
return;
|
||||
}
|
||||
if ((flist[n-1] = filter_find(trim(ptr))) == NULL)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Unable to find filter '%s' for service '%s'\n",
|
||||
"Warning : Unable to find filter '%s' for service '%s'\n",
|
||||
trim(ptr), service->name
|
||||
)));
|
||||
n--;
|
||||
@ -819,7 +818,7 @@ SERVICE *service;
|
||||
void
|
||||
printService(SERVICE *service)
|
||||
{
|
||||
SERVER *ptr = service->databases;
|
||||
SERVER_REF *ptr = service->dbref;
|
||||
struct tm result;
|
||||
char time_buf[30];
|
||||
int i;
|
||||
@ -832,8 +831,8 @@ int i;
|
||||
printf("\tBackend databases\n");
|
||||
while (ptr)
|
||||
{
|
||||
printf("\t\t%s:%d Protocol: %s\n", ptr->name, ptr->port, ptr->protocol);
|
||||
ptr = ptr->nextdb;
|
||||
printf("\t\t%s:%d Protocol: %s\n", ptr->server->name, ptr->server->port, ptr->server->protocol);
|
||||
ptr = ptr->next;
|
||||
}
|
||||
if (service->n_filters)
|
||||
{
|
||||
@ -900,7 +899,7 @@ SERVICE *ptr;
|
||||
*/
|
||||
void dprintService(DCB *dcb, SERVICE *service)
|
||||
{
|
||||
SERVER *server = service->databases;
|
||||
SERVER_REF *server = service->dbref;
|
||||
struct tm result;
|
||||
char timebuf[30];
|
||||
int i;
|
||||
@ -910,7 +909,22 @@ int i;
|
||||
service->name);
|
||||
dcb_printf(dcb, "\tRouter: %s (%p)\n",
|
||||
service->routerModule, service->router);
|
||||
if (service->router)
|
||||
switch (service->state)
|
||||
{
|
||||
case SERVICE_STATE_STARTED:
|
||||
dcb_printf(dcb, "\tState: Started\n");
|
||||
break;
|
||||
case SERVICE_STATE_STOPPED:
|
||||
dcb_printf(dcb, "\tState: Stopped\n");
|
||||
break;
|
||||
case SERVICE_STATE_FAILED:
|
||||
dcb_printf(dcb, "\tState: Failed\n");
|
||||
break;
|
||||
case SERVICE_STATE_ALLOC:
|
||||
dcb_printf(dcb, "\tState: Allocated\n");
|
||||
break;
|
||||
}
|
||||
if (service->router && service->router_instance)
|
||||
service->router->diagnostics(service->router_instance, dcb);
|
||||
dcb_printf(dcb, "\tStarted: %s",
|
||||
asctime_r(localtime_r(&service->stats.started, &result), timebuf));
|
||||
@ -929,9 +943,9 @@ int i;
|
||||
dcb_printf(dcb, "\tBackend databases\n");
|
||||
while (server)
|
||||
{
|
||||
dcb_printf(dcb, "\t\t%s:%d Protocol: %s\n", server->name, server->port,
|
||||
server->protocol);
|
||||
server = server->nextdb;
|
||||
dcb_printf(dcb, "\t\t%s:%d Protocol: %s\n", server->server->name, server->server->port,
|
||||
server->server->protocol);
|
||||
server = server->next;
|
||||
}
|
||||
if (service->weightby)
|
||||
dcb_printf(dcb, "\tRouting weight parameter: %s\n",
|
||||
@ -1397,3 +1411,16 @@ serviceEnableLocalhostMatchWildcardHost(SERVICE *service, int action)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void service_shutdown()
|
||||
{
|
||||
SERVICE* svc;
|
||||
spinlock_acquire(&service_spin);
|
||||
svc = allServices;
|
||||
while (svc != NULL)
|
||||
{
|
||||
svc->svc_do_shutdown = true;
|
||||
svc = svc->next;
|
||||
}
|
||||
spinlock_release(&service_spin);
|
||||
}
|
@ -85,12 +85,21 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
"session object due error %d, %s.",
|
||||
errno,
|
||||
strerror(errno))));
|
||||
if (client_dcb->data && !DCB_IS_CLONE(client_dcb))
|
||||
{
|
||||
free(client_dcb->data);
|
||||
client_dcb->data = NULL;
|
||||
}
|
||||
goto return_session;
|
||||
}
|
||||
#if defined(SS_DEBUG)
|
||||
session->ses_chk_top = CHK_NUM_SESSION;
|
||||
session->ses_chk_tail = CHK_NUM_SESSION;
|
||||
#endif
|
||||
if (DCB_IS_CLONE(client_dcb))
|
||||
{
|
||||
session->ses_is_child = true;
|
||||
}
|
||||
spinlock_init(&session->ses_lock);
|
||||
/*<
|
||||
* Prevent backend threads from accessing before session is completely
|
||||
@ -149,6 +158,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
* Decrease refcount, set dcb's session pointer NULL
|
||||
* and set session pointer to NULL.
|
||||
*/
|
||||
session->client = NULL;
|
||||
session_free(session);
|
||||
client_dcb->session = NULL;
|
||||
session = NULL;
|
||||
@ -189,6 +199,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
* Decrease refcount, set dcb's session pointer NULL
|
||||
* and set session pointer to NULL.
|
||||
*/
|
||||
session->client = NULL;
|
||||
session_free(session);
|
||||
client_dcb->session = NULL;
|
||||
session = NULL;
|
||||
@ -207,6 +218,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
if (session->state != SESSION_STATE_READY)
|
||||
{
|
||||
spinlock_release(&session->ses_lock);
|
||||
session->client = NULL;
|
||||
session_free(session);
|
||||
client_dcb->session = NULL;
|
||||
session = NULL;
|
||||
@ -331,12 +343,16 @@ int session_unlink_dcb(
|
||||
|
||||
if (nlink == 0)
|
||||
{
|
||||
session->state = SESSION_STATE_FREE;
|
||||
session->state = SESSION_STATE_TO_BE_FREED;
|
||||
}
|
||||
|
||||
if (dcb != NULL)
|
||||
{
|
||||
dcb->session = NULL;
|
||||
if (session->client == dcb)
|
||||
{
|
||||
session->client = NULL;
|
||||
}
|
||||
dcb->session = NULL;
|
||||
}
|
||||
spinlock_release(&session->ses_lock);
|
||||
|
||||
@ -357,7 +373,6 @@ bool session_free(
|
||||
int i;
|
||||
|
||||
CHK_SESSION(session);
|
||||
|
||||
/*<
|
||||
* Remove one reference. If there are no references left,
|
||||
* free session.
|
||||
@ -388,8 +403,12 @@ bool session_free(
|
||||
spinlock_release(&session_spin);
|
||||
atomic_add(&session->service->stats.n_current, -1);
|
||||
|
||||
/* Free router_session and session */
|
||||
if (session->router_session) {
|
||||
/**
|
||||
* If session is not child of some other session, free router_session.
|
||||
* Otherwise let the parent free it.
|
||||
*/
|
||||
if (!session->ses_is_child && session->router_session)
|
||||
{
|
||||
session->service->router->freeSession(
|
||||
session->service->router_instance,
|
||||
session->router_session);
|
||||
@ -422,7 +441,17 @@ bool session_free(
|
||||
/** Disable trace and decrease trace logger counter */
|
||||
session_disable_log(session, LT);
|
||||
|
||||
free(session);
|
||||
/** If session doesn't have parent referencing to it, it can be freed */
|
||||
if (!session->ses_is_child)
|
||||
{
|
||||
session->state = SESSION_STATE_FREE;
|
||||
|
||||
if (session->data)
|
||||
{
|
||||
free(session->data);
|
||||
}
|
||||
free(session);
|
||||
}
|
||||
succp = true;
|
||||
|
||||
return_succp :
|
||||
@ -687,6 +716,15 @@ session_state(int state)
|
||||
return "Listener Session";
|
||||
case SESSION_STATE_LISTENER_STOPPED:
|
||||
return "Stopped Listener Session";
|
||||
#ifdef SS_DEBUG
|
||||
case SESSION_STATE_STOPPING:
|
||||
return "Stopping session";
|
||||
case SESSION_STATE_TO_BE_FREED:
|
||||
return "Session to be freed";
|
||||
case SESSION_STATE_FREE:
|
||||
return "Freed session";
|
||||
|
||||
#endif
|
||||
default:
|
||||
return "Invalid State";
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ add_test(TestBuffer test_buffer)
|
||||
add_test(TestDCB test_dcb)
|
||||
add_test(TestModutil test_modutil)
|
||||
add_test(TestPoll test_poll)
|
||||
add_test(TestService test_service)
|
||||
add_test(TestService /bin/sh -c " MAXSCALE_HOME=${CMAKE_BINARY_DIR} && ${CMAKE_CURRENT_BINAR_DIR}/test_service")
|
||||
add_test(TestServer test_server)
|
||||
add_test(TestUsers test_users)
|
||||
add_test(TestAdminUsers test_adminusers)
|
||||
|
@ -272,6 +272,8 @@ char *home, buf[1024];
|
||||
if ((home = getenv("MAXSCALE_HOME")) == NULL || strlen(home) >= 1024)
|
||||
home = "/usr/local/skysql";
|
||||
sprintf(buf, "%s/etc/passwd", home);
|
||||
if(!is_valid_posix_path(buf))
|
||||
exit(1);
|
||||
if (strcmp(buf, "/etc/passwd") != 0)
|
||||
unlink(buf);
|
||||
|
||||
|
@ -49,11 +49,13 @@ HINT *hint;
|
||||
char* name = strdup("name");
|
||||
hint = hint_create_parameter(NULL, name, "value");
|
||||
free(name);
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(NULL != hint, "New hint list should not be null");
|
||||
ss_info_dassert(0 == strcmp("value", hint->value), "Hint value should be correct");
|
||||
ss_info_dassert(0 != hint_exists(&hint, HINT_PARAMETER), "Hint of parameter type should exist");
|
||||
ss_dfprintf(stderr, "\t..done\nFree hints.");
|
||||
if (NULL != hint) hint_free(hint);
|
||||
skygw_log_sync_all();
|
||||
ss_dfprintf(stderr, "\t..done\n");
|
||||
|
||||
return 0;
|
||||
|
@ -51,7 +51,7 @@ int result;
|
||||
"testpoll : Initialise the polling system.");
|
||||
poll_init();
|
||||
ss_dfprintf(stderr, "\t..done\nAdd a DCB");
|
||||
dcb = dcb_alloc(DCB_ROLE_SERVICE_LISTENER);
|
||||
dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
|
||||
|
||||
if(dcb == NULL){
|
||||
ss_dfprintf(stderr, "\nError on function call: dcb_alloc() returned NULL.\n");
|
||||
|
@ -48,7 +48,7 @@ char *status;
|
||||
ss_dfprintf(stderr,
|
||||
"testserver : creating server called MyServer");
|
||||
server = server_alloc("MyServer", "HTTPD", 9876);
|
||||
|
||||
skygw_log_sync_all();
|
||||
|
||||
//ss_info_dassert(NULL != service, "New server with valid protocol and port must not be null");
|
||||
//ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation");
|
||||
@ -56,26 +56,32 @@ char *status;
|
||||
ss_dfprintf(stderr, "\t..done\nTest Parameter for Server.");
|
||||
ss_info_dassert(NULL == serverGetParameter(server, "name"), "Parameter should be null when not set");
|
||||
serverAddParameter(server, "name", "value");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(0 == strcmp("value", serverGetParameter(server, "name")), "Parameter should be returned correctly");
|
||||
ss_dfprintf(stderr, "\t..done\nTesting Unique Name for Server.");
|
||||
ss_info_dassert(NULL == server_find_by_unique_name("uniquename"), "Should not find non-existent unique name.");
|
||||
server_set_unique_name(server, "uniquename");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(server == server_find_by_unique_name("uniquename"), "Should find by unique name.");
|
||||
ss_dfprintf(stderr, "\t..done\nTesting Status Setting for Server.");
|
||||
status = server_status(server);
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(0 == strcmp("Running", status), "Status of Server should be Running by default.");
|
||||
if (NULL != status) free(status);
|
||||
server_set_status(server, SERVER_MASTER);
|
||||
status = server_status(server);
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(0 == strcmp("Master, Running", status), "Should find correct status.");
|
||||
server_clear_status(server, SERVER_MASTER);
|
||||
free(status);
|
||||
status = server_status(server);
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(0 == strcmp("Running", status), "Status of Server should be Running after master status cleared.");
|
||||
if (NULL != status) free(status);
|
||||
ss_dfprintf(stderr, "\t..done\nRun Prints for Server and all Servers.");
|
||||
printServer(server);
|
||||
printAllServers();
|
||||
skygw_log_sync_all();
|
||||
ss_dfprintf(stderr, "\t..done\nFreeing Server.");
|
||||
ss_info_dassert(0 != server_free(server), "Free should succeed");
|
||||
ss_dfprintf(stderr, "\t..done\n");
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <maxscale_test.h>
|
||||
#include <service.h>
|
||||
|
||||
/**
|
||||
@ -42,15 +42,27 @@ test1()
|
||||
{
|
||||
SERVICE *service;
|
||||
int result;
|
||||
int argc = 3;
|
||||
char buffer[1024];
|
||||
sprintf(buffer,"%s",TEST_LOG_DIR);
|
||||
char* argv[] = {
|
||||
"log_manager",
|
||||
"-j",
|
||||
buffer,
|
||||
NULL
|
||||
};
|
||||
skygw_logmanager_init(argc,argv);
|
||||
|
||||
/* Service tests */
|
||||
ss_dfprintf(stderr,
|
||||
"testservice : creating service called MyService with router nonexistent");
|
||||
service = service_alloc("MyService", "non-existent");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(NULL == service, "New service with invalid router should be null");
|
||||
ss_info_dassert(0 == service_isvalid(service), "Service must not be valid after incorrect creation");
|
||||
ss_dfprintf(stderr, "\t..done\nValid service creation, router testroute.");
|
||||
service = service_alloc("MyService", "testroute");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(NULL != service, "New service with valid router must not be null");
|
||||
ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation");
|
||||
ss_info_dassert(0 == strcmp("MyService", service_get_name(service)), "Service must have given name");
|
||||
@ -58,12 +70,16 @@ int result;
|
||||
ss_info_dassert(0 != serviceAddProtocol(service, "HTTPD", "localhost", 9876), "Add Protocol should succeed");
|
||||
ss_info_dassert(0 != serviceHasProtocol(service, "HTTPD", 9876), "Service should have new protocol as requested");
|
||||
serviceStartProtocol(service, "HTTPD", 9876);
|
||||
skygw_log_sync_all();
|
||||
ss_dfprintf(stderr, "\t..done\nStarting Service.");
|
||||
result = serviceStart(service);
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(0 != result, "Start should succeed");
|
||||
result = serviceStop(service);
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(0 != result, "Stop should succeed");
|
||||
result = serviceStartAll();
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(0 != result, "Start all should succeed");
|
||||
|
||||
ss_dfprintf(stderr, "\t..done\nStopping Service.");
|
||||
|
@ -33,6 +33,8 @@
|
||||
|
||||
#include <users.h>
|
||||
|
||||
#include "log_manager.h"
|
||||
|
||||
/**
|
||||
* test1 Allocate table of users and mess around with it
|
||||
*
|
||||
@ -49,26 +51,34 @@ int result, count;
|
||||
ss_dfprintf(stderr,
|
||||
"testusers : Initialise the user table.");
|
||||
users = users_alloc();
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(NULL != users, "Allocating user table should not return NULL.")
|
||||
ss_dfprintf(stderr, "\t..done\nAdd a user");
|
||||
count = users_add(users, "username", "authorisation");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(1 == count, "Should add one user");
|
||||
authdata = users_fetch(users, "username");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(NULL != authdata, "Fetch valid user must not return NULL");
|
||||
ss_info_dassert(0 == strcmp("authorisation", authdata), "User authorisation should be correct");
|
||||
ss_dfprintf(stderr, "\t..done\nPrint users");
|
||||
usersPrint(users);
|
||||
skygw_log_sync_all();
|
||||
ss_dfprintf(stderr, "\t..done\nUpdate a user");
|
||||
count = users_update(users, "username", "newauth");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(1 == count, "Should update just one user");
|
||||
authdata = users_fetch(users, "username");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(NULL != authdata, "Fetch valid user must not return NULL");
|
||||
ss_info_dassert(0 == strcmp("newauth", authdata), "User authorisation should be correctly updated");
|
||||
ss_dfprintf(stderr, "\t..done\nDelete a user.");
|
||||
count = users_delete(users, "username");
|
||||
skygw_log_sync_all();
|
||||
ss_info_dassert(1 == count, "Should delete just one user");
|
||||
ss_dfprintf(stderr, "\t..done\nFree user table.");
|
||||
users_free(users);
|
||||
skygw_log_sync_all();
|
||||
ss_dfprintf(stderr, "\t..done\n");
|
||||
|
||||
return 0;
|
||||
|
@ -183,32 +183,41 @@ char *sep;
|
||||
void *user;
|
||||
|
||||
dcb_printf(dcb, "Users table data\n");
|
||||
dcb_hashtable_stats(dcb, users->data);
|
||||
if ((iter = hashtable_iterator(users->data)) != NULL)
|
||||
|
||||
if (users == NULL || users->data == NULL)
|
||||
{
|
||||
dcb_printf(dcb, "User names: ");
|
||||
sep = "";
|
||||
dcb_printf(dcb, "Users table is empty\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb_hashtable_stats(dcb, users->data);
|
||||
|
||||
if ((iter = hashtable_iterator(users->data)) != NULL)
|
||||
{
|
||||
dcb_printf(dcb, "User names: ");
|
||||
sep = "";
|
||||
|
||||
if (users->usersCustomUserFormat != NULL) {
|
||||
while ((user = hashtable_next(iter)) != NULL)
|
||||
{
|
||||
char *custom_user;
|
||||
custom_user = users->usersCustomUserFormat(user);
|
||||
if (custom_user) {
|
||||
dcb_printf(dcb, "%s%s", sep, custom_user);
|
||||
free(custom_user);
|
||||
if (users->usersCustomUserFormat != NULL) {
|
||||
while ((user = hashtable_next(iter)) != NULL)
|
||||
{
|
||||
char *custom_user;
|
||||
custom_user = users->usersCustomUserFormat(user);
|
||||
if (custom_user) {
|
||||
dcb_printf(dcb, "%s%s", sep, custom_user);
|
||||
free(custom_user);
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while ((user = hashtable_next(iter)) != NULL)
|
||||
{
|
||||
dcb_printf(dcb, "%s%s", sep, (char *)user);
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while ((user = hashtable_next(iter)) != NULL)
|
||||
{
|
||||
dcb_printf(dcb, "%s%s", sep, (char *)user);
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
|
||||
dcb_printf(dcb, "\n");
|
||||
hashtable_iterator_free(iter);
|
||||
hashtable_iterator_free(iter);
|
||||
}
|
||||
}
|
||||
dcb_printf(dcb, "\n");
|
||||
}
|
||||
|
Reference in New Issue
Block a user