diff --git a/server/core/server.c b/server/core/server.c index 9841b96ff..79e457612 100644 --- a/server/core/server.c +++ b/server/core/server.c @@ -575,3 +575,75 @@ SERVER_PARAM *param = server->parameters; } return NULL; } + +/** + * Provide a row to the result set that defines the set of servers + * + * @param set The result set + * @param data The index of the row to send + * @return The next row or NULL + */ +static RESULT_ROW * +serverRowCallback(RESULTSET *set, void *data) +{ +int *rowno = (int *)data; +int i = 0;; +char *stat, buf[20]; +RESULT_ROW *row; +SERVER *ptr; + + spinlock_acquire(&server_spin); + ptr = allServers; + while (i < *rowno && ptr) + { + i++; + ptr = ptr->next; + } + if (ptr == NULL) + { + spinlock_release(&server_spin); + free(data); + return NULL; + } + (*rowno)++; + row = resultset_make_row(set); + resultset_row_set(row, 0, ptr->unique_name); + resultset_row_set(row, 1, ptr->name); + sprintf(buf, "%d", ptr->port); + resultset_row_set(row, 2, buf); + sprintf(buf, "%d", ptr->stats.n_current); + resultset_row_set(row, 3, buf); + stat = server_status(ptr); + resultset_row_set(row, 4, stat); + free(stat); + spinlock_release(&server_spin); + return row; +} + +/** + * Return a resultset that has the current set of servers in it + * + * @return A Result set + */ +RESULTSET * +serverGetList() +{ +RESULTSET *set; +int *data; + + if ((data = (int *)malloc(sizeof(int))) == NULL) + return NULL; + *data = 0; + if ((set = resultset_create(serverRowCallback, data)) == NULL) + { + free(data); + return NULL; + } + resultset_add_column(set, "Server", 20, COL_TYPE_VARCHAR); + resultset_add_column(set, "Address", 15, COL_TYPE_VARCHAR); + resultset_add_column(set, "Port", 5, COL_TYPE_VARCHAR); + resultset_add_column(set, "Connections", 8, COL_TYPE_VARCHAR); + resultset_add_column(set, "Status", 20, COL_TYPE_VARCHAR); + + return set; +} diff --git a/server/core/service.c b/server/core/service.c index 98aa8b458..52a4ea370 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -1536,6 +1536,92 @@ int rval = 0; return rval; } +/** + * Provide a row to the result set that defines the set of service + * listeners + * + * @param set The result set + * @param data The index of the row to send + * @return The next row or NULL + */ +static RESULT_ROW * +serviceListenerRowCallback(RESULTSET *set, void *data) +{ +int *rowno = (int *)data; +int i = 0;; +char buf[20]; +RESULT_ROW *row; +SERVICE *ptr; +SERV_PROTOCOL *lptr = NULL; + + spinlock_acquire(&service_spin); + ptr = allServices; + if (ptr) + lptr = ptr->ports; + while (i < *rowno && ptr) + { + lptr = ptr->ports; + while (i < *rowno && lptr) + { + if ((lptr = lptr->next) != NULL) + i++; + } + if (i < *rowno) + { + ptr = ptr->next; + if (ptr && (lptr = ptr->ports) != NULL) + i++; + } + } + if (lptr == NULL) + { + spinlock_release(&service_spin); + free(data); + return NULL; + } + (*rowno)++; + row = resultset_make_row(set); + resultset_row_set(row, 0, ptr->name); + resultset_row_set(row, 1, lptr->protocol); + resultset_row_set(row, 2, (lptr && lptr->address) ? lptr->address : "*"); + sprintf(buf, "%d", lptr->port); + resultset_row_set(row, 3, buf); + resultset_row_set(row, 4, + (!lptr->listener || !lptr->listener->session || + lptr->listener->session->state == SESSION_STATE_LISTENER_STOPPED) ? + "Stopped" : "Running"); + spinlock_release(&service_spin); + return row; +} + +/** + * Return a resultset that has the current set of services in it + * + * @return A Result set + */ +RESULTSET * +serviceGetListenerList() +{ +RESULTSET *set; +int *data; + + if ((data = (int *)malloc(sizeof(int))) == NULL) + return NULL; + *data = 0; + if ((set = resultset_create(serviceListenerRowCallback, data)) == NULL) + { + free(data); + return NULL; + } + resultset_add_column(set, "Service Name", 25, COL_TYPE_VARCHAR); + resultset_add_column(set, "Protocol Module", 20, COL_TYPE_VARCHAR); + resultset_add_column(set, "Address", 15, COL_TYPE_VARCHAR); + resultset_add_column(set, "Port", 5, COL_TYPE_VARCHAR); + resultset_add_column(set, "State", 8, COL_TYPE_VARCHAR); + + return set; +} + /** * Provide a row to the result set that defines the set of services * @@ -1556,8 +1642,8 @@ SERVICE *ptr; ptr = allServices; while (i < *rowno && ptr) { - ptr = ptr->next; i++; + ptr = ptr->next; } if (ptr == NULL) { @@ -1596,8 +1682,8 @@ int *data; free(data); return NULL; } - resultset_add_column(set, "Name", 30, COL_TYPE_VARCHAR); - resultset_add_column(set, "Router Module", 30, COL_TYPE_VARCHAR); + resultset_add_column(set, "Service Name", 25, COL_TYPE_VARCHAR); + resultset_add_column(set, "Router Module", 20, COL_TYPE_VARCHAR); resultset_add_column(set, "No. Sessions", 10, COL_TYPE_VARCHAR); resultset_add_column(set, "Total Sessions", 10, COL_TYPE_VARCHAR); diff --git a/server/core/session.c b/server/core/session.c index fb1dda79f..53ee92d56 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -909,3 +909,101 @@ SESSION *get_all_sessions() { return allSessions; } + +/** + * Callback structure for the session lsit extraction + */ +typedef struct { + int index; + SESSIONLISTFILTER filter; +} SESSIONFILTER; + +/** + * Provide a row to the result set that defines the set of sessions + * + * @param set The result set + * @param data The index of the row to send + * @return The next row or NULL + */ +static RESULT_ROW * +sessionRowCallback(RESULTSET *set, void *data) +{ +SESSIONFILTER *cbdata = (SESSIONFILTER *)data; +int i = 0; +char buf[20]; +RESULT_ROW *row; +SESSION *ptr; + + spinlock_acquire(&session_spin); + ptr = allSessions; + /* Skip to the first non-listener if not showing listeners */ + while (ptr && cbdata->filter == SESSION_LIST_CONNECTION && + ptr->state == SESSION_STATE_LISTENER) + { + ptr = ptr->next; + } + while (i < cbdata->index && ptr) + { + if (cbdata->filter == SESSION_LIST_CONNECTION && + ptr->state != SESSION_STATE_LISTENER) + { + i++; + } + else if (cbdata->filter == SESSION_LIST_ALL) + { + i++; + } + ptr = ptr->next; + } + /* Skip to the next non-listener if not showing listeners */ + while (ptr && cbdata->filter == SESSION_LIST_CONNECTION && + ptr->state == SESSION_STATE_LISTENER) + { + ptr = ptr->next; + } + if (ptr == NULL) + { + spinlock_release(&session_spin); + free(data); + return NULL; + } + cbdata->index++; + row = resultset_make_row(set); + sprintf(buf, "%p", ptr); + resultset_row_set(row, 0, buf); + resultset_row_set(row, 1, ((ptr->client && ptr->client->remote) + ? ptr->client->remote : "")); + resultset_row_set(row, 2, (ptr->service && ptr->service->name + ? ptr->service->name : "")); + resultset_row_set(row, 3, session_state(ptr->state)); + spinlock_release(&session_spin); + return row; +} + +/** + * Return a resultset that has the current set of sessions in it + * + * @return A Result set + */ +RESULTSET * +sessionGetList(SESSIONLISTFILTER filter) +{ +RESULTSET *set; +SESSIONFILTER *data; + + if ((data = (SESSIONFILTER *)malloc(sizeof(SESSIONFILTER))) == NULL) + return NULL; + data->index = 0; + data->filter = filter; + if ((set = resultset_create(sessionRowCallback, data)) == NULL) + { + free(data); + return NULL; + } + resultset_add_column(set, "Session", 16, COL_TYPE_VARCHAR); + resultset_add_column(set, "Client", 15, COL_TYPE_VARCHAR); + resultset_add_column(set, "Service", 15, COL_TYPE_VARCHAR); + resultset_add_column(set, "State", 15, COL_TYPE_VARCHAR); + + return set; +} diff --git a/server/include/server.h b/server/include/server.h index 4bb514d65..e309d6196 100644 --- a/server/include/server.h +++ b/server/include/server.h @@ -18,6 +18,7 @@ * Copyright MariaDB Corporation Ab 2013-2014 */ #include +#include /** * @file service.h @@ -41,6 +42,7 @@ * 30/07/14 Massimiliano Pinto Addition of NDB status for MySQL Cluster * 30/08/14 Massimiliano Pinto Addition of SERVER_STALE_STATUS * 27/10/14 Massimiliano Pinto Addition of SERVER_MASTER_STICKINESS + * 19/02/15 Mark Riddoch Addition of serverGetList * * @endverbatim */ @@ -186,4 +188,5 @@ extern void serverAddParameter(SERVER *, char *, char *); extern char *serverGetParameter(SERVER *, char *); extern void server_update(SERVER *, char *, char *, char *); extern void server_set_unique_name(SERVER *, char *); +extern RESULTSET *serverGetList(); #endif diff --git a/server/include/service.h b/server/include/service.h index 720c961da..1ecfb54e7 100644 --- a/server/include/service.h +++ b/server/include/service.h @@ -196,4 +196,5 @@ char* service_get_name(SERVICE* svc); void service_shutdown(); extern int serviceSessionCountAll(); extern RESULTSET *serviceGetList(); +extern RESULTSET *serviceGetListenerList(); #endif diff --git a/server/include/session.h b/server/include/session.h index e008cc4ff..738679f9d 100644 --- a/server/include/session.h +++ b/server/include/session.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,14 @@ typedef struct { void *session; } SESSION_FILTER; +/** + * Filter type for the sessionGetList call + */ +typedef enum { + SESSION_LIST_ALL, + SESSION_LIST_CONNECTION +} SESSIONLISTFILTER; + /** * The session status block * @@ -167,5 +176,5 @@ bool session_link_dcb(SESSION *, struct dcb *); SESSION* get_session_by_router_ses(void* rses); void session_enable_log(SESSION* ses, logfile_id_t id); void session_disable_log(SESSION* ses, logfile_id_t id); - +RESULTSET *sessionGetList(SESSIONLISTFILTER); #endif diff --git a/server/modules/routing/maxinfo/maxinfo_exec.c b/server/modules/routing/maxinfo/maxinfo_exec.c index e489c722f..027e77f8a 100644 --- a/server/modules/routing/maxinfo/maxinfo_exec.c +++ b/server/modules/routing/maxinfo/maxinfo_exec.c @@ -86,6 +86,12 @@ maxinfo_execute(DCB *dcb, MAXINFO_TREE *tree) } } +/** + * Fetch the list of services and stream as a result set + * + * @param dcb DCB to which to stream result set + * @param tree Potential liek clause (currently unused) + */ static void exec_show_services(DCB *dcb, MAXINFO_TREE *tree) { @@ -98,6 +104,81 @@ RESULTSET *set; resultset_free(set); } +/** + * Fetch the list of listeners and stream as a result set + * + * @param dcb DCB to which to stream result set + * @param tree Potential liek clause (currently unused) + */ +static void +exec_show_listeners(DCB *dcb, MAXINFO_TREE *tree) +{ +RESULTSET *set; + + if ((set = serviceGetListenerList()) == NULL) + return; + + resultset_stream_mysql(set, dcb); + resultset_free(set); +} + +/** + * Fetch the list of sessions and stream as a result set + * + * @param dcb DCB to which to stream result set + * @param tree Potential liek clause (currently unused) + */ +static void +exec_show_sessions(DCB *dcb, MAXINFO_TREE *tree) +{ +RESULTSET *set; + + if ((set = sessionGetList(SESSION_LIST_ALL)) == NULL) + return; + + resultset_stream_mysql(set, dcb); + resultset_free(set); +} + +/** + * Fetch the list of client sessions and stream as a result set + * + * @param dcb DCB to which to stream result set + * @param tree Potential liek clause (currently unused) + */ +static void +exec_show_clients(DCB *dcb, MAXINFO_TREE *tree) +{ +RESULTSET *set; + + if ((set = sessionGetList(SESSION_LIST_CONNECTION)) == NULL) + return; + + resultset_stream_mysql(set, dcb); + resultset_free(set); +} + +/** + * Fetch the list of servers and stream as a result set + * + * @param dcb DCB to which to stream result set + * @param tree Potential liek clause (currently unused) + */ +static void +exec_show_servers(DCB *dcb, MAXINFO_TREE *tree) +{ +RESULTSET *set; + + if ((set = serverGetList(SESSION_LIST_CONNECTION)) == NULL) + return; + + resultset_stream_mysql(set, dcb); + resultset_free(set); +} + +/** + * The table of show commands that are supported + */ static struct { char *name; void (*func)(DCB *, MAXINFO_TREE *); @@ -105,6 +186,10 @@ static struct { { "variables", exec_show_variables }, { "status", exec_show_status }, { "services", exec_show_services }, + { "listeners", exec_show_listeners }, + { "sessions", exec_show_sessions }, + { "clients", exec_show_clients }, + { "servers", exec_show_servers }, { NULL, NULL } };