diff --git a/server/core/dcb.c b/server/core/dcb.c index 4a83dc3b0..604989f21 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -1264,6 +1264,41 @@ DCB *dcb; spinlock_release(&dcbspin); } +/** + * Diagnotic routine to print client DCB data in a tabular form. + * + * @param pdcb DCB to print results to + */ +void +dListClients(DCB *pdcb) +{ +DCB *dcb; + + spinlock_acquire(&dcbspin); + dcb = allDCBs; + dcb_printf(pdcb, "Client Connections\n"); + dcb_printf(pdcb, "-----------------+------------+----------------------+------------\n"); + dcb_printf(pdcb, " %-15s | %-10s | %-20s | %s\n", + "Client", "DCB", "Service", "Session"); + dcb_printf(pdcb, "-----------------+------------+----------------------+------------\n"); + while (dcb) + { + if (dcb_isclient(dcb) + && dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER) + { + dcb_printf(pdcb, " %-15s | %10p | %-20s | %10p\n", + (dcb->remote ? dcb->remote : ""), + dcb, (dcb->session->service ? + dcb->session->service->name : ""), + dcb->session); + } + dcb = dcb->next; + } + dcb_printf(pdcb, "-----------------+------------+----------------------+------------\n\n"); + spinlock_release(&dcbspin); +} + + /** * Diagnostic to print a DCB to another DCB * @@ -1275,8 +1310,14 @@ dprintDCB(DCB *pdcb, DCB *dcb) { dcb_printf(pdcb, "DCB: %p\n", (void *)dcb); dcb_printf(pdcb, "\tDCB state: %s\n", gw_dcb_state2string(dcb->state)); + if (dcb->session && dcb->session->service) + dcb_printf(pdcb, "\tService: %s\n", + dcb->session->service->name); if (dcb->remote) dcb_printf(pdcb, "\tConnected to: %s\n", dcb->remote); + if (dcb->user) + dcb_printf(pdcb, "\tUsername: %s\n", + dcb->user); dcb_printf(pdcb, "\tOwning Session: %p\n", dcb->session); if (dcb->writeq) dcb_printf(pdcb, "\tQueued write data: %d\n", gwbuf_length(dcb->writeq)); diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 50efc5c89..4d4bd1f35 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -378,7 +378,9 @@ MODULES *ptr = registered; : (ptr->info->status == MODULE_BETA_RELEASE ? "Beta" : (ptr->info->status == MODULE_GA - ? "GA" : "Unknown")))); + ? "GA" + : (ptr->info->status == MODULE_EXPERIMENTAL + ? "Experimental" : "Unknown"))))); dcb_printf(dcb, "\n"); ptr = ptr->next; } diff --git a/server/core/monitor.c b/server/core/monitor.c index 2fca9bcac..784abdc5b 100644 --- a/server/core/monitor.c +++ b/server/core/monitor.c @@ -73,6 +73,7 @@ MONITOR *mon; return NULL; } mon->handle = (*mon->module->startMonitor)(NULL); + mon->state |= MONITOR_RUNNING; spinlock_acquire(&monLock); mon->next = allMonitors; allMonitors = mon; @@ -93,6 +94,7 @@ monitor_free(MONITOR *mon) MONITOR *ptr; mon->module->stopMonitor(mon->handle); + mon->state &= ~MONITOR_RUNNING; spinlock_acquire(&monLock); if (allMonitors == mon) allMonitors = mon->next; @@ -119,6 +121,7 @@ void monitorStart(MONITOR *monitor) { monitor->handle = (*monitor->module->startMonitor)(monitor->handle); + monitor->state |= MONITOR_RUNNING; } /** @@ -130,6 +133,7 @@ void monitorStop(MONITOR *monitor) { monitor->module->stopMonitor(monitor->handle); + monitor->state &= ~MONITOR_RUNNING; } /** @@ -200,6 +204,46 @@ MONITOR *ptr; spinlock_release(&monLock); } +/** + * Show a single monitor + * + * @param dcb DCB for printing output + */ +void +monitorShow(DCB *dcb, MONITOR *monitor) +{ + + dcb_printf(dcb, "Monitor: %p\n", monitor); + dcb_printf(dcb, "\tName: %s\n", monitor->name); + if (monitor->module->diagnostics) + monitor->module->diagnostics(dcb, monitor->handle); +} + +/** + * List all the monitors + * + * @param dcb DCB for printing output + */ +void +monitorList(DCB *dcb) +{ +MONITOR *ptr; + + spinlock_acquire(&monLock); + ptr = allMonitors; + dcb_printf(dcb, "+----------------------+---------------------\n"); + dcb_printf(dcb, "| %-20s | Status\n", "Monitor"); + dcb_printf(dcb, "+----------------------+---------------------\n"); + while (ptr) + { + dcb_printf(dcb, "| %-20s | %s\n", ptr->name, + ptr->state & MONITOR_RUNNING ? "Running" : "Stopped"); + ptr = ptr->next; + } + dcb_printf(dcb, "+----------------------+---------------------\n"); + spinlock_release(&monLock); +} + /** * Find a monitor by name * @@ -249,6 +293,7 @@ void monitorSetInterval (MONITOR *mon, unsigned long interval) { if (mon->module->setInterval != NULL) { + mon->interval = interval; mon->module->setInterval(mon->handle, interval); } } diff --git a/server/core/server.c b/server/core/server.c index c1bec6189..e2e9c2bc2 100644 --- a/server/core/server.c +++ b/server/core/server.c @@ -292,7 +292,8 @@ char *stat; } } if (server->node_ts > 0) { - dcb_printf(dcb, "\tLast Repl Heartbeat:\t%lu\n", server->node_ts); + dcb_printf(dcb, "\tLast Repl Heartbeat:\t%s", + asctime(localtime(&server->node_ts))); } dcb_printf(dcb, "\tNumber of connections: %d\n", server->stats.n_connections); dcb_printf(dcb, "\tCurrent no. of conns: %d\n", server->stats.n_current); diff --git a/server/include/dcb.h b/server/include/dcb.h index 3a2cace5c..3d068bc2b 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -282,6 +282,7 @@ void printDCB(DCB *); /* Debug print routine */ void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */ void dprintDCB(DCB *, DCB *); /* Debug to print a DCB in the system */ void dListDCBs(DCB *); /* List all DCBs in the system */ +void dListClients(DCB *); /* List al the client DCBs */ 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 */ diff --git a/server/include/modinfo.h b/server/include/modinfo.h index c3c1e64da..bc4107b39 100644 --- a/server/include/modinfo.h +++ b/server/include/modinfo.h @@ -38,7 +38,8 @@ typedef enum { MODULE_IN_DEVELOPMENT = 0, MODULE_ALPHA_RELEASE, MODULE_BETA_RELEASE, - MODULE_GA + MODULE_GA, + MODULE_EXPERIMENTAL } MODULE_STATUS; /** diff --git a/server/include/monitor.h b/server/include/monitor.h index 861c1c070..f953f3057 100644 --- a/server/include/monitor.h +++ b/server/include/monitor.h @@ -78,13 +78,21 @@ typedef struct { */ #define MONITOR_VERSION {1, 0, 0} +/** + * Monitor state bit mask values + */ +#define MONITOR_RUNNING 0x0001 + + /** * Representation of the running monitor. */ typedef struct monitor { char *name; /**< The name of the monitor module */ + unsigned int state; /**< The monitor status */ MONITOR_OBJECT *module; /**< The "monitor object" */ void *handle; /**< Handle returned from startMonitor */ + int interval; /**< The monitor interval */ struct monitor *next; /**< Next monitor in the linked list */ } MONITOR; @@ -97,6 +105,8 @@ extern void monitorStop(MONITOR *); extern void monitorStart(MONITOR *); extern void monitorStopAll(); extern void monitorShowAll(DCB *); +extern void monitorShow(DCB *, MONITOR *); +extern void monitorList(DCB *); extern void monitorSetId(MONITOR *, unsigned long); extern void monitorSetInterval (MONITOR *, unsigned long); extern void monitorSetReplicationHeartbeat(MONITOR *, int); diff --git a/server/modules/filter/qlafilter.c b/server/modules/filter/qlafilter.c index bc3e4622d..818c1a6f1 100644 --- a/server/modules/filter/qlafilter.c +++ b/server/modules/filter/qlafilter.c @@ -390,11 +390,24 @@ struct timeval tv; static void diagnostic(FILTER *instance, void *fsession, DCB *dcb) { +QLA_INSTANCE *my_instance = (QLA_INSTANCE *)instance; QLA_SESSION *my_session = (QLA_SESSION *)fsession; if (my_session) { - dcb_printf(dcb, "\t\tLogging to file %s.\n", + dcb_printf(dcb, "\t\tLogging to file %s.\n", my_session->filename); } + if (my_instance->source) + dcb_printf(dcb, "\t\tLimit logging to connections from %s\n", + my_instance->source); + if (my_instance->userName) + dcb_printf(dcb, "\t\tLimit logging to user %s\n", + my_instance->userName); + if (my_instance->match) + dcb_printf(dcb, "\t\tInclude queries that match %s\n", + my_instance->match); + if (my_instance->nomatch) + dcb_printf(dcb, "\t\tExclude queries that match %s\n", + my_instance->nomatch); } diff --git a/server/modules/filter/regexfilter.c b/server/modules/filter/regexfilter.c index 69c00c930..aae2dfa3a 100644 --- a/server/modules/filter/regexfilter.c +++ b/server/modules/filter/regexfilter.c @@ -345,6 +345,14 @@ REGEX_SESSION *my_session = (REGEX_SESSION *)fsession; dcb_printf(dcb, "\t\tNo. of queries altered by filter: %d\n", my_session->replacements); } + if (my_instance->source) + dcb_printf(dcb, + "\t\tReplacement limited to connections from %s\n", + my_instance->source); + if (my_instance->user) + dcb_printf(dcb, + "\t\tReplacement limit to user %s\n", + my_instance->user); } /** diff --git a/server/modules/filter/tee.c b/server/modules/filter/tee.c index 211fbbd70..06dc39251 100644 --- a/server/modules/filter/tee.c +++ b/server/modules/filter/tee.c @@ -118,7 +118,8 @@ typedef struct { int active; /* filter is active? */ DCB *branch_dcb; /* Client DCB for "branch" service */ SESSION *branch_session;/* The branch service session */ - int n_duped; /* Number of duplicated querise */ + int n_duped; /* Number of duplicated queries */ + int n_rejected; /* Number of rejected queries */ int residual; /* Any outstanding SQL text */ } TEE_SESSION; @@ -418,6 +419,10 @@ GWBUF *clone = NULL; my_session->n_duped++; SESSION_ROUTE_QUERY(my_session->branch_session, clone); } + else + { + my_session->n_rejected++; + } return rval; } @@ -435,11 +440,28 @@ GWBUF *clone = NULL; static void diagnostic(FILTER *instance, void *fsession, DCB *dcb) { +TEE_INSTANCE *my_instance = (TEE_INSTANCE *)instance; TEE_SESSION *my_session = (TEE_SESSION *)fsession; + if (my_instance->source) + dcb_printf(dcb, "\t\tLimit to connections from %s\n", + my_instance->source); + dcb_printf(dcb, "\t\tDuplicate statements to service %s\n", + my_instance->service->name); + if (my_instance->userName) + dcb_printf(dcb, "\t\tLimit to user %s\n", + my_instance->userName); + if (my_instance->match) + dcb_printf(dcb, "\t\tInclude queries that match %s\n", + my_instance->match); + if (my_instance->nomatch) + dcb_printf(dcb, "\t\tExclude queries that match %s\n", + my_instance->nomatch); if (my_session) { dcb_printf(dcb, "\t\tNo. of statements duplicated: %d.\n", my_session->n_duped); + dcb_printf(dcb, "\t\tNo. of statements rejected: %d.\n", + my_session->n_rejected); } } diff --git a/server/modules/filter/topfilter.c b/server/modules/filter/topfilter.c index cc13ed6c4..62781fe22 100644 --- a/server/modules/filter/topfilter.c +++ b/server/modules/filter/topfilter.c @@ -539,11 +539,40 @@ int i, inserted; static void diagnostic(FILTER *instance, void *fsession, DCB *dcb) { +TOPN_INSTANCE *my_instance = (TOPN_INSTANCE *)instance; TOPN_SESSION *my_session = (TOPN_SESSION *)fsession; +int i; + dcb_printf(dcb, "\t\tReport size %d\n", + my_instance->topN); + if (my_instance->source) + dcb_printf(dcb, "\t\tLimit logging to connections from %s\n", + my_instance->source); + if (my_instance->user) + dcb_printf(dcb, "\t\tLimit logging to user %s\n", + my_instance->user); + if (my_instance->match) + dcb_printf(dcb, "\t\tInclude queries that match %s\n", + my_instance->match); + if (my_instance->exclude) + dcb_printf(dcb, "\t\tExclude queries that match %s\n", + my_instance->exclude); if (my_session) { dcb_printf(dcb, "\t\tLogging to file %s.\n", my_session->filename); + dcb_printf(dcb, "\t\tCurrent Top %d:\n", my_instance->topN); + for (i = 0; i < my_instance->topN; i++) + { + if (my_session->top[i]->sql) + { + dcb_printf(dcb, "\t\t%d place:\n", i + 1); + dcb_printf(dcb, "\t\t\tExecution time: %.3f seconds\n", + (double)((my_session->top[i]->duration.tv_sec * 1000) + + (my_session->top[i]->duration.tv_usec / 1000)) / 1000); + dcb_printf(dcb, "\t\t\tSQL: %s\n", + my_session->top[i]->sql); + } + } } } diff --git a/server/modules/routing/debugcmd.c b/server/modules/routing/debugcmd.c index 914ba888e..a9a5da12a 100644 --- a/server/modules/routing/debugcmd.c +++ b/server/modules/routing/debugcmd.c @@ -128,6 +128,10 @@ struct subcommand showoptions[] = { "Show all currently loaded modules", "Show all currently loaded modules", {0, 0, 0} }, + { "monitor", 1, monitorShow, + "Show the monitor details", + "Show the monitor details", + {ARG_TYPE_MONITOR, 0, 0} }, { "monitors", 0, monitorShowAll, "Show the monitors that are configured", "Show the monitors that are configured", @@ -168,6 +172,10 @@ struct subcommand showoptions[] = { * The subcommands of the list command */ struct subcommand listoptions[] = { + { "clients", 0, dListClients, + "List all the client connections to MaxScale", + "List all the client connections to MaxScale", + {0, 0, 0} }, { "dcbs", 0, dListDCBs, "List all the DCBs active within MaxScale", "List all the DCBs active within MaxScale", @@ -181,8 +189,12 @@ struct subcommand listoptions[] = { "List all the listeners defined within MaxScale", {0, 0, 0} }, { "modules", 0, dprintAllModules, - "Show all currently loaded modules", - "Show all currently loaded modules", + "List all currently loaded modules", + "List all currently loaded modules", + {0, 0, 0} }, + { "monitors", 0, monitorList, + "List all monitors", + "List all monitors", {0, 0, 0} }, { "services", 0, dListServices, "List all the services defined within MaxScale", @@ -307,11 +319,23 @@ struct subcommand reloadoptions[] = { static void enable_log_action(DCB *, char *); static void disable_log_action(DCB *, char *); +static void enable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor); +static void disable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor); +static void enable_service_root(DCB *dcb, SERVICE *service); +static void disable_service_root(DCB *dcb, SERVICE *service); /** * * The subcommands of the enable command * */ struct subcommand enableoptions[] = { + { + "heartbeat", + 1, + enable_monitor_replication_heartbeat, + "Enable the monitor replication heartbeat, pass a monitor name as argument", + "Enable the monitor replication heartbeat, pass a monitor name as argument", + {ARG_TYPE_MONITOR, 0, 0} + }, { "log", 1, @@ -322,6 +346,14 @@ struct subcommand enableoptions[] = { "message E.g. enable log message.", {ARG_TYPE_STRING, 0, 0} }, + { + "root", + 1, + enable_service_root, + "Enable root access to a service, pass a service name to enable root access", + "Enable root access to a service, pass a service name to enable root access", + {ARG_TYPE_SERVICE, 0, 0} + }, { NULL, 0, @@ -337,24 +369,40 @@ struct subcommand enableoptions[] = { * * The subcommands of the disable command * */ struct subcommand disableoptions[] = { - { - "log", - 1, - disable_log_action, - "Disable Log for MaxScale, Options: debug | trace | error | message " - "E.g. disable log debug", - "Disable Log for MaxScale, Options: debug | trace | error | message " - "E.g. disable log debug", - {ARG_TYPE_STRING, 0, 0} - }, - { + { + "heartbeat", + 1, + disable_monitor_replication_heartbeat, + "Disable the monitor replication heartbeat", + "Disable the monitor replication heartbeat", + {ARG_TYPE_MONITOR, 0, 0} + }, + { + "log", + 1, + disable_log_action, + "Disable Log for MaxScale, Options: debug | trace | error | message " + "E.g. disable log debug", + "Disable Log for MaxScale, Options: debug | trace | error | message " + "E.g. disable log debug", + {ARG_TYPE_STRING, 0, 0} + }, + { + "root", + 1, + disable_service_root, + "Disable root access to a service", + "Disable root access to a service", + {ARG_TYPE_SERVICE, 0, 0} + }, + { NULL, 0, NULL, NULL, NULL, {0, 0, 0} - } + } }; #if defined(SS_DEBUG) @@ -850,7 +898,7 @@ unsigned int bitvalue; static void reload_dbusers(DCB *dcb, SERVICE *service) { - dcb_printf(dcb, "Loaded %d database users for server %s.\n", + dcb_printf(dcb, "Loaded %d database users for service %s.\n", reload_mysql_users(service), service->name); } @@ -958,6 +1006,55 @@ restart_monitor(DCB *dcb, MONITOR *monitor) monitorStart(monitor); } +/** + * Enable replication heartbeat for a monitor + * + * @param dcb Connection to user interface + * @param monitor The monitor + */ +static void +enable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor) +{ + monitorSetReplicationHeartbeat(monitor, 1); +} + +/** + * Disable replication heartbeat for a monitor + * + * @param dcb Connection to user interface + * @param monitor The monitor + */ +static void +disable_monitor_replication_heartbeat(DCB *dcb, MONITOR *monitor) +{ + monitorSetReplicationHeartbeat(monitor, 0); +} + +/** + * Enable root access to a service + * + * @param dcb Connection to user interface + * @param service The service + */ +static void +enable_service_root(DCB *dcb, SERVICE *service) +{ + serviceEnableRootUser(service, 1); +} + +/** + * Disable root access to a service + * + * @param dcb Connection to user interface + * @param service The service + */ +static void +disable_service_root(DCB *dcb, SERVICE *service) +{ + serviceEnableRootUser(service, 0); +} + + /** * The log enable action */