diff --git a/server/modules/routing/avrorouter/avro.c b/server/modules/routing/avrorouter/avro.c index 4bb1ab0cb..233258adb 100644 --- a/server/modules/routing/avrorouter/avro.c +++ b/server/modules/routing/avrorouter/avro.c @@ -76,7 +76,8 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *instance, MXS_SESSION *session static void closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static void freeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static int routeQuery(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue); -static json_t* diagnostics(const MXS_ROUTER *instance); +static void diagnostics(MXS_ROUTER *instance, DCB *dcb); +static json_t* diagnostics_json(const MXS_ROUTER *instance); static void clientReply(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue, DCB *backend_dcb); static void errorReply(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *message, @@ -157,6 +158,7 @@ MXS_MODULE* MXS_CREATE_MODULE() freeSession, routeQuery, diagnostics, + diagnostics_json, clientReply, errorReply, getCapabilities, @@ -806,8 +808,111 @@ routeQuery(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queu * Display router diagnostics * * @param instance Instance of the router + * @param dcb DCB to send diagnostics to */ -static json_t* diagnostics(const MXS_ROUTER *router) +static void +diagnostics(MXS_ROUTER *router, DCB *dcb) +{ + AVRO_INSTANCE *router_inst = (AVRO_INSTANCE *) router; + AVRO_CLIENT *session; + int i = 0; + char buf[40]; + struct tm tm; + + spinlock_acquire(&router_inst->lock); + session = router_inst->clients; + while (session) + { + i++; + session = session->next; + } + spinlock_release(&router_inst->lock); + + dcb_printf(dcb, "\tAVRO Converter infofile: %s/%s\n", + router_inst->avrodir, AVRO_PROGRESS_FILE); + dcb_printf(dcb, "\tAVRO files directory: %s\n", + router_inst->avrodir); + + localtime_r(&router_inst->stats.lastReply, &tm); + asctime_r(&tm, buf); + + dcb_printf(dcb, "\tBinlog directory: %s\n", + router_inst->binlogdir); + dcb_printf(dcb, "\tCurrent binlog file: %s\n", + router_inst->binlog_name); + dcb_printf(dcb, "\tCurrent binlog position: %lu\n", + router_inst->current_pos); + dcb_printf(dcb, "\tCurrent GTID value: %lu-%lu-%lu\n", + router_inst->gtid.domain, router_inst->gtid.server_id, + router_inst->gtid.seq); + dcb_printf(dcb, "\tCurrent GTID timestamp: %u\n", + router_inst->gtid.timestamp); + dcb_printf(dcb, "\tCurrent GTID #events: %lu\n", + router_inst->gtid.event_num); + + dcb_printf(dcb, "\tCurrent GTID affected tables: "); + avro_get_used_tables(router_inst, dcb); + dcb_printf(dcb, "\n"); + + dcb_printf(dcb, "\tNumber of AVRO clients: %u\n", + router_inst->stats.n_clients); + + if (router_inst->clients) + { + dcb_printf(dcb, "\tClients:\n"); + spinlock_acquire(&router_inst->lock); + session = router_inst->clients; + while (session) + { + + char sync_marker_hex[SYNC_MARKER_SIZE * 2 + 1]; + + dcb_printf(dcb, "\t\tClient UUID: %s\n", session->uuid); + dcb_printf(dcb, "\t\tClient_host_port: [%s]:%d\n", + session->dcb->remote, dcb_get_port(session->dcb)); + dcb_printf(dcb, "\t\tUsername: %s\n", session->dcb->user); + dcb_printf(dcb, "\t\tClient DCB: %p\n", session->dcb); + dcb_printf(dcb, "\t\tClient protocol: %s\n", + session->dcb->service->ports->protocol); + dcb_printf(dcb, "\t\tClient Output Format: %s\n", + avro_client_ouput[session->format]); + dcb_printf(dcb, "\t\tState: %s\n", + avro_client_states[session->state]); + dcb_printf(dcb, "\t\tAvro file: %s\n", session->avro_binfile); + + gw_bin2hex(sync_marker_hex, session->avro_file.sync, SYNC_MARKER_SIZE); + + dcb_printf(dcb, "\t\tAvro file SyncMarker: %s\n", sync_marker_hex); + dcb_printf(dcb, "\t\tAvro file last read block: %lu\n", + session->avro_file.blocks_read); + dcb_printf(dcb, "\t\tAvro file last read record: %lu\n", + session->avro_file.records_read); + + if (session->gtid_start.domain > 0 || session->gtid_start.server_id > 0 || + session->gtid_start.seq > 0) + { + dcb_printf(dcb, "\t\tRequested GTID: %lu-%lu-%lu\n", + session->gtid_start.domain, session->gtid_start.server_id, + session->gtid_start.seq); + } + + dcb_printf(dcb, "\t\tCurrent GTID: %lu-%lu-%lu\n", + session->gtid.domain, session->gtid.server_id, + session->gtid.seq); + + dcb_printf(dcb, "\t\t--------------------\n\n"); + session = session->next; + } + spinlock_release(&router_inst->lock); + } +} + +/** + * Display router diagnostics + * + * @param instance Instance of the router + */ +static json_t* diagnostics_json(const MXS_ROUTER *router) { AVRO_INSTANCE *router_inst = (AVRO_INSTANCE *)router; diff --git a/server/modules/routing/binlogrouter/blr.c b/server/modules/routing/binlogrouter/blr.c index 4ae20776e..b16ad78ee 100644 --- a/server/modules/routing/binlogrouter/blr.c +++ b/server/modules/routing/binlogrouter/blr.c @@ -95,7 +95,8 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *instance, MXS_SESSION *sessio static void closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static void freeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static int routeQuery(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue); -static json_t* diagnostics(const MXS_ROUTER *instance); +static void diagnostics(MXS_ROUTER *instance, DCB *dcb); +static json_t* diagnostics_json(const MXS_ROUTER *instance); static void clientReply(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue, @@ -160,6 +161,7 @@ MXS_MODULE* MXS_CREATE_MODULE() freeSession, routeQuery, diagnostics, + diagnostics_json, clientReply, errorReply, getCapabilities, @@ -1287,7 +1289,450 @@ spin_reporter(void *dcb, char *desc, int value) * @param instance Instance of the router * @param dcb DCB to send diagnostics to */ -static json_t* diagnostics(const MXS_ROUTER *router) +static void +diagnostics(MXS_ROUTER *router, DCB *dcb) +{ + ROUTER_INSTANCE *router_inst = (ROUTER_INSTANCE *)router; + ROUTER_SLAVE *session; + int i = 0, j; + int minno = 0; + double min5, min10, min15, min30; + char buf[40]; + struct tm tm; + + spinlock_acquire(&router_inst->lock); + session = router_inst->slaves; + while (session) + { + i++; + session = session->next; + } + spinlock_release(&router_inst->lock); + + minno = router_inst->stats.minno; + min30 = 0.0; + min15 = 0.0; + min10 = 0.0; + min5 = 0.0; + for (j = 0; j < BLR_NSTATS_MINUTES; j++) + { + minno--; + if (minno < 0) + { + minno += BLR_NSTATS_MINUTES; + } + min30 += router_inst->stats.minavgs[minno]; + if (j < 15) + { + min15 += router_inst->stats.minavgs[minno]; + } + if (j < 10) + { + min10 += router_inst->stats.minavgs[minno]; + } + if (j < 5) + { + min5 += router_inst->stats.minavgs[minno]; + } + } + min30 /= 30.0; + min15 /= 15.0; + min10 /= 10.0; + min5 /= 5.0; + + if (router_inst->master) + { + dcb_printf(dcb, "\tMaster connection DCB: %p\n", + router_inst->master); + } + else + { + dcb_printf(dcb, "\tMaster connection DCB: 0x0\n"); + } + + /* SSL options */ + if (router_inst->ssl_enabled) + { + dcb_printf(dcb, "\tMaster SSL is ON:\n"); + if (router_inst->service->dbref->server && router_inst->service->dbref->server->server_ssl) + { + dcb_printf(dcb, "\t\tMaster SSL CA cert: %s\n", + router_inst->service->dbref->server->server_ssl->ssl_ca_cert); + dcb_printf(dcb, "\t\tMaster SSL Cert: %s\n", + router_inst->service->dbref->server->server_ssl->ssl_cert); + dcb_printf(dcb, "\t\tMaster SSL Key: %s\n", + router_inst->service->dbref->server->server_ssl->ssl_key); + dcb_printf(dcb, "\t\tMaster SSL tls_ver: %s\n", + router_inst->ssl_version ? router_inst->ssl_version : "MAX"); + } + } + + /* Binlog Encryption options */ + if (router_inst->encryption.enabled) + { + dcb_printf(dcb, "\tBinlog Encryption is ON:\n"); + dcb_printf(dcb, "\t\tEncryption Key File: %s\n", + router_inst->encryption.key_management_filename); + dcb_printf(dcb, "\t\tEncryption Key Algorithm: %s\n", + blr_get_encryption_algorithm(router_inst->encryption.encryption_algorithm)); + dcb_printf(dcb, "\t\tEncryption Key length: %lu bits\n", + 8 * router_inst->encryption.key_len); + } + + dcb_printf(dcb, "\tMaster connection state: %s\n", + blrm_states[router_inst->master_state]); + + localtime_r(&router_inst->stats.lastReply, &tm); + asctime_r(&tm, buf); + + dcb_printf(dcb, "\tBinlog directory: %s\n", + router_inst->binlogdir); + dcb_printf(dcb, "\tHeartbeat period (seconds): %lu\n", + router_inst->heartbeat); + dcb_printf(dcb, "\tNumber of master connects: %d\n", + router_inst->stats.n_masterstarts); + dcb_printf(dcb, "\tNumber of delayed reconnects: %d\n", + router_inst->stats.n_delayedreconnects); + dcb_printf(dcb, "\tCurrent binlog file: %s\n", + router_inst->binlog_name); + dcb_printf(dcb, "\tCurrent binlog position: %lu\n", + router_inst->current_pos); + if (router_inst->trx_safe) + { + if (router_inst->pending_transaction.state != BLRM_NO_TRANSACTION) + { + dcb_printf(dcb, "\tCurrent open transaction pos: %lu\n", + router_inst->binlog_position); + } + } + dcb_printf(dcb, "\tNumber of slave servers: %u\n", + router_inst->stats.n_slaves); + dcb_printf(dcb, "\tNo. of binlog events received this session: %lu\n", + router_inst->stats.n_binlogs_ses); + dcb_printf(dcb, "\tTotal no. of binlog events received: %lu\n", + router_inst->stats.n_binlogs); + dcb_printf(dcb, "\tNo. of bad CRC received from master: %u\n", + router_inst->stats.n_badcrc); + minno = router_inst->stats.minno - 1; + if (minno == -1) + { + minno += BLR_NSTATS_MINUTES; + } + dcb_printf(dcb, "\tNumber of binlog events per minute\n"); + dcb_printf(dcb, "\tCurrent 5 10 15 30 Min Avg\n"); + dcb_printf(dcb, "\t %6d %8.1f %8.1f %8.1f %8.1f\n", + router_inst->stats.minavgs[minno], min5, min10, min15, min30); + dcb_printf(dcb, "\tNumber of fake binlog events: %lu\n", + router_inst->stats.n_fakeevents); + dcb_printf(dcb, "\tNumber of artificial binlog events: %lu\n", + router_inst->stats.n_artificial); + dcb_printf(dcb, "\tNumber of binlog events in error: %lu\n", + router_inst->stats.n_binlog_errors); + dcb_printf(dcb, "\tNumber of binlog rotate events: %lu\n", + router_inst->stats.n_rotates); + dcb_printf(dcb, "\tNumber of heartbeat events: %u\n", + router_inst->stats.n_heartbeats); + dcb_printf(dcb, "\tNumber of packets received: %u\n", + router_inst->stats.n_reads); + dcb_printf(dcb, "\tNumber of residual data packets: %u\n", + router_inst->stats.n_residuals); + dcb_printf(dcb, "\tAverage events per packet: %.1f\n", + router_inst->stats.n_reads != 0 ? + ((double)router_inst->stats.n_binlogs / router_inst->stats.n_reads) : 0); + + spinlock_acquire(&router_inst->lock); + if (router_inst->stats.lastReply) + { + if (buf[strlen(buf) - 1] == '\n') + { + buf[strlen(buf) - 1] = '\0'; + } + dcb_printf(dcb, "\tLast event from master at: %s (%ld seconds ago)\n", + buf, time(0) - router_inst->stats.lastReply); + + if (!router_inst->mariadb10_compat) + { + dcb_printf(dcb, "\tLast event from master: 0x%x, %s\n", + router_inst->lastEventReceived, + (router_inst->lastEventReceived <= MAX_EVENT_TYPE) ? + event_names[router_inst->lastEventReceived] : "unknown"); + } + else + { + char *ptr = NULL; + if (router_inst->lastEventReceived <= MAX_EVENT_TYPE) + { + ptr = event_names[router_inst->lastEventReceived]; + } + else + { + /* Check MariaDB 10 new events */ + if (router_inst->lastEventReceived >= MARIADB_NEW_EVENTS_BEGIN && + router_inst->lastEventReceived <= MAX_EVENT_TYPE_MARIADB10) + { + ptr = event_names_mariadb10[(router_inst->lastEventReceived - MARIADB_NEW_EVENTS_BEGIN)]; + } + } + + dcb_printf(dcb, "\tLast event from master: 0x%x, %s\n", + router_inst->lastEventReceived, (ptr != NULL) ? ptr : "unknown"); + + if (router_inst->mariadb_gtid && + router_inst->last_mariadb_gtid[0]) + { + dcb_printf(dcb, "\tLast seen MariaDB GTID: %s\n", + router_inst->last_mariadb_gtid); + } + } + + if (router_inst->lastEventTimestamp) + { + time_t last_event = (time_t)router_inst->lastEventTimestamp; + localtime_r(&last_event, &tm); + asctime_r(&tm, buf); + if (buf[strlen(buf) - 1] == '\n') + { + buf[strlen(buf) - 1] = '\0'; + } + dcb_printf(dcb, "\tLast binlog event timestamp: %u (%s)\n", + router_inst->lastEventTimestamp, buf); + } + } + else + { + dcb_printf(dcb, "\tNo events received from master yet\n"); + } + spinlock_release(&router_inst->lock); + + if (router_inst->active_logs) + { + dcb_printf(dcb, "\tRouter processing binlog records\n"); + } + if (router_inst->reconnect_pending) + { + dcb_printf(dcb, "\tRouter pending reconnect to master\n"); + } + dcb_printf(dcb, "\tEvents received:\n"); + for (i = 0; i <= MAX_EVENT_TYPE; i++) + { + dcb_printf(dcb, "\t\t%-38s %lu\n", event_names[i], router_inst->stats.events[i]); + } + + if (router_inst->mariadb10_compat) + { + /* Display MariaDB 10 new events */ + for (i = MARIADB_NEW_EVENTS_BEGIN; i <= MAX_EVENT_TYPE_MARIADB10; i++) + { + dcb_printf(dcb, "\t\tMariaDB 10 %-38s %lu\n", + event_names_mariadb10[(i - MARIADB_NEW_EVENTS_BEGIN)], + router_inst->stats.events[i]); + } + } + +#if SPINLOCK_PROFILE + dcb_printf(dcb, "\tSpinlock statistics (instlock):\n"); + spinlock_stats(&instlock, spin_reporter, dcb); + dcb_printf(dcb, "\tSpinlock statistics (instance lock):\n"); + spinlock_stats(&router_inst->lock, spin_reporter, dcb); + dcb_printf(dcb, "\tSpinlock statistics (binlog position lock):\n"); + spinlock_stats(&router_inst->binlog_lock, spin_reporter, dcb); +#endif + + if (router_inst->slaves) + { + dcb_printf(dcb, "\tSlaves:\n"); + spinlock_acquire(&router_inst->lock); + session = router_inst->slaves; + while (session) + { + + minno = session->stats.minno; + min30 = 0.0; + min15 = 0.0; + min10 = 0.0; + min5 = 0.0; + for (j = 0; j < BLR_NSTATS_MINUTES; j++) + { + minno--; + if (minno < 0) + { + minno += BLR_NSTATS_MINUTES; + } + min30 += session->stats.minavgs[minno]; + if (j < 15) + { + min15 += session->stats.minavgs[minno]; + } + if (j < 10) + { + min10 += session->stats.minavgs[minno]; + } + if (j < 5) + { + min5 += session->stats.minavgs[minno]; + } + } + min30 /= 30.0; + min15 /= 15.0; + min10 /= 10.0; + min5 /= 5.0; + dcb_printf(dcb, + "\t\tServer-id: %d\n", + session->serverid); + if (session->hostname) + { + dcb_printf(dcb, + "\t\tHostname: %s\n", session->hostname); + } + if (session->uuid) + { + dcb_printf(dcb, "\t\tSlave UUID: %s\n", session->uuid); + } + dcb_printf(dcb, + "\t\tSlave_host_port: [%s]:%d\n", + session->dcb->remote, dcb_get_port(session->dcb)); + dcb_printf(dcb, + "\t\tUsername: %s\n", + session->dcb->user); + dcb_printf(dcb, + "\t\tSlave DCB: %p\n", + session->dcb); + if (session->dcb->ssl) + { + dcb_printf(dcb, + "\t\tSlave connected with SSL: %s\n", + session->dcb->ssl_state == SSL_ESTABLISHED ? + "Established" : "Not connected yet"); + } + dcb_printf(dcb, + "\t\tNext Sequence No: %d\n", + session->seqno); + dcb_printf(dcb, + "\t\tState: %s\n", + blrs_states[session->state]); + dcb_printf(dcb, + "\t\tBinlog file: %s\n", + session->binlogfile); + dcb_printf(dcb, + "\t\tBinlog position: %u\n", + session->binlog_pos); + if (session->nocrc) + { + dcb_printf(dcb, + "\t\tMaster Binlog CRC: None\n"); + } + dcb_printf(dcb, + "\t\tNo. requests: %u\n", + session->stats.n_requests); + dcb_printf(dcb, + "\t\tNo. events sent: %u\n", + session->stats.n_events); + dcb_printf(dcb, + "\t\tNo. bytes sent: %lu\n", + session->stats.n_bytes); + dcb_printf(dcb, + "\t\tNo. bursts sent: %u\n", + session->stats.n_bursts); + dcb_printf(dcb, + "\t\tNo. transitions to follow mode: %u\n", + session->stats.n_bursts); + if (router_inst->send_slave_heartbeat) + { + dcb_printf(dcb, + "\t\tHeartbeat period (seconds): %d\n", + session->heartbeat); + } + + minno = session->stats.minno - 1; + if (minno == -1) + { + minno += BLR_NSTATS_MINUTES; + } + dcb_printf(dcb, "\t\tNumber of binlog events per minute\n"); + dcb_printf(dcb, "\t\tCurrent 5 10 15 30 Min Avg\n"); + dcb_printf(dcb, "\t\t %6d %8.1f %8.1f %8.1f %8.1f\n", + session->stats.minavgs[minno], min5, min10, + min15, min30); + dcb_printf(dcb, "\t\tNo. flow control: %u\n", + session->stats.n_flows); + dcb_printf(dcb, "\t\tNo. up to date: %u\n", + session->stats.n_upd); + dcb_printf(dcb, "\t\tNo. of drained cbs %u\n", + session->stats.n_dcb); + dcb_printf(dcb, "\t\tNo. of failed reads %u\n", + session->stats.n_failed_read); + +#ifdef DETAILED_DIAG + dcb_printf(dcb, "\t\tNo. of nested distribute events %u\n", + session->stats.n_overrun); + dcb_printf(dcb, "\t\tNo. of distribute action 1 %u\n", + session->stats.n_actions[0]); + dcb_printf(dcb, "\t\tNo. of distribute action 2 %u\n", + session->stats.n_actions[1]); + dcb_printf(dcb, "\t\tNo. of distribute action 3 %u\n", + session->stats.n_actions[2]); +#endif + if (session->lastEventTimestamp + && router_inst->lastEventTimestamp && session->lastEventReceived != HEARTBEAT_EVENT) + { + unsigned long seconds_behind; + time_t session_last_event = (time_t)session->lastEventTimestamp; + + if (router_inst->lastEventTimestamp > session->lastEventTimestamp) + { + seconds_behind = router_inst->lastEventTimestamp - session->lastEventTimestamp; + } + else + { + seconds_behind = 0; + } + + localtime_r(&session_last_event, &tm); + asctime_r(&tm, buf); + dcb_printf(dcb, "\t\tLast binlog event timestamp %u, %s", + session->lastEventTimestamp, buf); + dcb_printf(dcb, "\t\tSeconds behind master %lu\n", + seconds_behind); + } + + if (session->state == 0) + { + dcb_printf(dcb, "\t\tSlave_mode: connected\n"); + } + else + { + if ((session->cstate & CS_WAIT_DATA) == CS_WAIT_DATA) + { + dcb_printf(dcb, "\t\tSlave_mode: wait-for-data\n"); + } + else + { + dcb_printf(dcb, "\t\tSlave_mode: catchup. %s%s\n", + ((session->cstate & CS_EXPECTCB) == 0 ? "" : + "Waiting for DCB queue to drain."), + ((session->cstate & CS_BUSY) == 0 ? "" : + " Busy in slave catchup.")); + } + } +#if SPINLOCK_PROFILE + dcb_printf(dcb, "\tSpinlock statistics (catch_lock):\n"); + spinlock_stats(&session->catch_lock, spin_reporter, dcb); + dcb_printf(dcb, "\tSpinlock statistics (rses_lock):\n"); + spinlock_stats(&session->rses_lock, spin_reporter, dcb); +#endif + dcb_printf(dcb, "\t\t--------------------\n\n"); + session = session->next; + } + spinlock_release(&router_inst->lock); + } +} + +/** + * Display router diagnostics + * + * @param instance Instance of the router + */ +static json_t* diagnostics_json(const MXS_ROUTER *router) { ROUTER_INSTANCE *router_inst = (ROUTER_INSTANCE *)router; int minno = 0; diff --git a/server/modules/routing/cli/cli.c b/server/modules/routing/cli/cli.c index fe7e4e797..dbd7e3919 100644 --- a/server/modules/routing/cli/cli.c +++ b/server/modules/routing/cli/cli.c @@ -48,7 +48,8 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *instance, MXS_SESSION *sessio static void closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static void freeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static int execute(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue); -static json_t* diagnostics(const MXS_ROUTER *instance); +static void diagnostics(MXS_ROUTER *instance, DCB *dcb); +static json_t* diagnostics_json(const MXS_ROUTER *instance); static uint64_t getCapabilities(MXS_ROUTER* instance); extern int execute_cmd(CLI_SESSION *cli); @@ -78,6 +79,7 @@ MXS_MODULE* MXS_CREATE_MODULE() freeSession, execute, diagnostics, + diagnostics_json, NULL, NULL, getCapabilities, @@ -284,7 +286,13 @@ execute(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue) * @param instance Instance of the router * @param dcb DCB to send diagnostics to */ -static json_t* diagnostics(const MXS_ROUTER *instance) +static void +diagnostics(MXS_ROUTER *instance, DCB *dcb) +{ + return; /* Nothing to do currently */ +} + +static json_t* diagnostics_json(const MXS_ROUTER *instance) { return NULL; } diff --git a/server/modules/routing/debugcli/debugcli.c b/server/modules/routing/debugcli/debugcli.c index 83e6afa82..ef3610be5 100644 --- a/server/modules/routing/debugcli/debugcli.c +++ b/server/modules/routing/debugcli/debugcli.c @@ -47,7 +47,8 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *instance, MXS_SESSION *sessio static void closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static void freeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static int execute(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue); -static json_t* diagnostics(const MXS_ROUTER *instance); +static void diagnostics(MXS_ROUTER *instance, DCB *dcb); +static json_t* diagnostics_json(const MXS_ROUTER *instance); static uint64_t getCapabilities(MXS_ROUTER* instance); extern int execute_cmd(CLI_SESSION *cli); @@ -77,6 +78,7 @@ MXS_MODULE* MXS_CREATE_MODULE() freeSession, execute, diagnostics, + diagnostics_json, NULL, NULL, getCapabilities, @@ -287,7 +289,19 @@ execute(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue) * @param instance Instance of the router * @param dcb DCB to send diagnostics to */ -static json_t* diagnostics(const MXS_ROUTER *instance) +static void +diagnostics(MXS_ROUTER *instance, DCB *dcb) +{ + return; /* Nothing to do currently */ +} + +/** + * Display router diagnostics + * + * @param instance Instance of the router + * @param dcb DCB to send diagnostics to + */ +static json_t* diagnostics_json(const MXS_ROUTER *instance) { return NULL; } diff --git a/server/modules/routing/hintrouter/hintrouter.cc b/server/modules/routing/hintrouter/hintrouter.cc index 061ff8693..79db39110 100644 --- a/server/modules/routing/hintrouter/hintrouter.cc +++ b/server/modules/routing/hintrouter/hintrouter.cc @@ -144,7 +144,26 @@ HintRouterSession* HintRouter::newSession(MXS_SESSION *pSession) return rval; } -json_t* HintRouter::diagnostics() const +void HintRouter::diagnostics(DCB* pOut) +{ + HR_ENTRY(); + for (int i = 0; default_action_values[i].name; i++) + { + if (default_action_values[i].enum_value == (uint64_t)m_default_action) + { + dcb_printf(pOut, "\tDefault action: route to %s\n", default_action_values[i].name); + } + } + dcb_printf(pOut, "\tDefault server: %s\n", m_default_server.c_str()); + dcb_printf(pOut, "\tMaximum slave connections/session: %d\n", m_max_slaves); + dcb_printf(pOut, "\tTotal cumulative slave connections: %d\n", m_total_slave_conns); + dcb_printf(pOut, "\tQueries routed to master: %d\n", m_routed_to_master); + dcb_printf(pOut, "\tQueries routed to single slave: %d\n", m_routed_to_slave); + dcb_printf(pOut, "\tQueries routed to named server: %d\n", m_routed_to_named); + dcb_printf(pOut, "\tQueries routed to all servers: %d\n", m_routed_to_all); +} + +json_t* HintRouter::diagnostics_json() const { HR_ENTRY(); diff --git a/server/modules/routing/hintrouter/hintrouter.hh b/server/modules/routing/hintrouter/hintrouter.hh index f4dcad722..e072ba837 100644 --- a/server/modules/routing/hintrouter/hintrouter.hh +++ b/server/modules/routing/hintrouter/hintrouter.hh @@ -22,7 +22,8 @@ class HintRouter : public maxscale::Router public: static HintRouter* create(SERVICE* pService, char** pzOptions); HintRouterSession* newSession(MXS_SESSION *pSession); - json_t* diagnostics() const; + void diagnostics(DCB* pOut); + json_t* diagnostics_json() const; uint64_t getCapabilities() const { return RCAP_TYPE_NONE; diff --git a/server/modules/routing/maxinfo/maxinfo.c b/server/modules/routing/maxinfo/maxinfo.c index 80164a065..c84093aac 100644 --- a/server/modules/routing/maxinfo/maxinfo.c +++ b/server/modules/routing/maxinfo/maxinfo.c @@ -69,7 +69,8 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *instance, MXS_SESSION *sessio static void closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static void freeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static int execute(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue); -static json_t* diagnostics(const MXS_ROUTER *instance); +static void diagnostics(MXS_ROUTER *instance, DCB *dcb); +static json_t* diagnostics_json(const MXS_ROUTER *instance); static uint64_t getCapabilities(MXS_ROUTER* instance); static void handleError(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, @@ -103,6 +104,7 @@ MXS_MODULE* MXS_CREATE_MODULE() freeSession, execute, diagnostics, + diagnostics_json, NULL, handleError, getCapabilities, @@ -362,6 +364,18 @@ execute(MXS_ROUTER *rinstance, MXS_ROUTER_SESSION *router_session, GWBUF *queue) return rc; } +/** + * Display router diagnostics + * + * @param instance Instance of the router + * @param dcb DCB to send diagnostics to + */ +static void +diagnostics(MXS_ROUTER *instance, DCB *dcb) +{ + return; /* Nothing to do currently */ +} + /** * Display router diagnostics * @@ -369,7 +383,7 @@ execute(MXS_ROUTER *rinstance, MXS_ROUTER_SESSION *router_session, GWBUF *queue) * @param dcb DCB to send diagnostics to */ static json_t* -diagnostics(const MXS_ROUTER *instance) +diagnostics_json(const MXS_ROUTER *instance) { return NULL; } diff --git a/server/modules/routing/readconnroute/readconnroute.c b/server/modules/routing/readconnroute/readconnroute.c index 7573da13b..d0816b742 100644 --- a/server/modules/routing/readconnroute/readconnroute.c +++ b/server/modules/routing/readconnroute/readconnroute.c @@ -93,7 +93,8 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *instance, MXS_SESSION *session static void closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static void freeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session); static int routeQuery(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue); -static json_t* diagnostics(const MXS_ROUTER *instance); +static void diagnostics(MXS_ROUTER *instance, DCB *dcb); +static json_t* diagnostics_json(const MXS_ROUTER *instance); static void clientReply(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue, DCB *backend_dcb); static void handleError(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *errbuf, @@ -123,6 +124,7 @@ MXS_MODULE* MXS_CREATE_MODULE() freeSession, routeQuery, diagnostics, + diagnostics_json, clientReply, handleError, getCapabilities, @@ -615,7 +617,43 @@ return_rc: * @param instance Instance of the router * @param dcb DCB to send diagnostics to */ -static json_t* diagnostics(const MXS_ROUTER *router) +static void +diagnostics(MXS_ROUTER *router, DCB *dcb) +{ + ROUTER_INSTANCE *router_inst = (ROUTER_INSTANCE *) router; + char *weightby; + + dcb_printf(dcb, "\tNumber of router sessions: %d\n", + router_inst->stats.n_sessions); + dcb_printf(dcb, "\tCurrent no. of router sessions: %d\n", + router_inst->service->stats.n_current); + dcb_printf(dcb, "\tNumber of queries forwarded: %d\n", + router_inst->stats.n_queries); + if ((weightby = serviceGetWeightingParameter(router_inst->service)) + != NULL) + { + dcb_printf(dcb, "\tConnection distribution based on %s " + "server parameter.\n", + weightby); + dcb_printf(dcb, + "\t\tServer Target %% Connections\n"); + for (SERVER_REF *ref = router_inst->service->dbref; ref; ref = ref->next) + { + dcb_printf(dcb, "\t\t%-20s %3.1f%% %d\n", + ref->server->unique_name, + (float) ref->weight / 10, + ref->connections); + } + } +} + +/** + * Display router diagnostics + * + * @param instance Instance of the router + * @param dcb DCB to send diagnostics to + */ +static json_t* diagnostics_json(const MXS_ROUTER *router) { ROUTER_INSTANCE *router_inst = (ROUTER_INSTANCE *)router; json_t* rval = json_object(); diff --git a/server/modules/routing/readwritesplit/readwritesplit.c b/server/modules/routing/readwritesplit/readwritesplit.c index f6ebdd1a3..ac0f35b2a 100644 --- a/server/modules/routing/readwritesplit/readwritesplit.c +++ b/server/modules/routing/readwritesplit/readwritesplit.c @@ -74,7 +74,8 @@ static MXS_ROUTER_SESSION *newSession(MXS_ROUTER *instance, MXS_SESSION *session static void closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *session); static void freeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *session); static int routeQuery(MXS_ROUTER *instance, MXS_ROUTER_SESSION *session, GWBUF *queue); -static json_t* diagnostics(const MXS_ROUTER *instance); +static void diagnostics(MXS_ROUTER *instance, DCB *dcb); +static json_t* diagnostics_json(const MXS_ROUTER *instance); static void clientReply(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, GWBUF *queue, DCB *backend_dcb); static void handleError(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, @@ -151,6 +152,7 @@ MXS_MODULE *MXS_CREATE_MODULE() freeSession, routeQuery, diagnostics, + diagnostics_json, clientReply, handleError, getCapabilities, @@ -646,7 +648,80 @@ static int routeQuery(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session, * @param instance The router instance * @param dcb The DCB for diagnostic output */ -static json_t* diagnostics(const MXS_ROUTER *instance) +static void diagnostics(MXS_ROUTER *instance, DCB *dcb) +{ + ROUTER_INSTANCE *router = (ROUTER_INSTANCE *)instance; + char *weightby; + double master_pct = 0.0, slave_pct = 0.0, all_pct = 0.0; + + dcb_printf(dcb, "\n"); + dcb_printf(dcb, "\tuse_sql_variables_in: %s\n", + mxs_target_to_str(router->rwsplit_config.use_sql_variables_in)); + dcb_printf(dcb, "\tslave_selection_criteria: %s\n", + select_criteria_to_str(router->rwsplit_config.slave_selection_criteria)); + dcb_printf(dcb, "\tmaster_failure_mode: %s\n", + failure_mode_to_str(router->rwsplit_config.master_failure_mode)); + dcb_printf(dcb, "\tmax_slave_replication_lag: %d\n", + router->rwsplit_config.max_slave_replication_lag); + dcb_printf(dcb, "\tretry_failed_reads: %s\n", + router->rwsplit_config.retry_failed_reads ? "true" : "false"); + dcb_printf(dcb, "\tstrict_multi_stmt: %s\n", + router->rwsplit_config.strict_multi_stmt ? "true" : "false"); + dcb_printf(dcb, "\tdisable_sescmd_history: %s\n", + router->rwsplit_config.disable_sescmd_history ? "true" : "false"); + dcb_printf(dcb, "\tmax_sescmd_history: %d\n", + router->rwsplit_config.max_sescmd_history); + dcb_printf(dcb, "\tmaster_accept_reads: %s\n", + router->rwsplit_config.master_accept_reads ? "true" : "false"); + dcb_printf(dcb, "\n"); + + if (router->stats.n_queries > 0) + { + master_pct = ((double)router->stats.n_master / (double)router->stats.n_queries) * 100.0; + slave_pct = ((double)router->stats.n_slave / (double)router->stats.n_queries) * 100.0; + all_pct = ((double)router->stats.n_all / (double)router->stats.n_queries) * 100.0; + } + + dcb_printf(dcb, "\tNumber of router sessions: %" PRIu64 "\n", + router->stats.n_sessions); + dcb_printf(dcb, "\tCurrent no. of router sessions: %d\n", + router->service->stats.n_current); + dcb_printf(dcb, "\tNumber of queries forwarded: %" PRIu64 "\n", + router->stats.n_queries); + dcb_printf(dcb, "\tNumber of queries forwarded to master: %" PRIu64 " (%.2f%%)\n", + router->stats.n_master, master_pct); + dcb_printf(dcb, "\tNumber of queries forwarded to slave: %" PRIu64 " (%.2f%%)\n", + router->stats.n_slave, slave_pct); + dcb_printf(dcb, "\tNumber of queries forwarded to all: %" PRIu64 " (%.2f%%)\n", + router->stats.n_all, all_pct); + + if ((weightby = serviceGetWeightingParameter(router->service)) != NULL) + { + dcb_printf(dcb, "\tConnection distribution based on %s " + "server parameter.\n", + weightby); + dcb_printf(dcb, "\t\tServer Target %% Connections " + "Operations\n"); + dcb_printf(dcb, "\t\t Global Router\n"); + for (SERVER_REF *ref = router->service->dbref; ref; ref = ref->next) + { + dcb_printf(dcb, "\t\t%-20s %3.1f%% %-6d %-6d %d\n", + ref->server->unique_name, (float)ref->weight / 10, + ref->server->stats.n_current, ref->connections, + ref->server->stats.n_current_ops); + } + } +} + +/** + * @brief Diagnostics routine (API) + * + * Print query router statistics to the DCB passed in + * + * @param instance The router instance + * @param dcb The DCB for diagnostic output + */ +static json_t* diagnostics_json(const MXS_ROUTER *instance) { ROUTER_INSTANCE *router = (ROUTER_INSTANCE *)instance; diff --git a/server/modules/routing/schemarouter/schemarouterinstance.cc b/server/modules/routing/schemarouter/schemarouterinstance.cc index ac28ee1df..2b71b16e8 100644 --- a/server/modules/routing/schemarouter/schemarouterinstance.cc +++ b/server/modules/routing/schemarouter/schemarouterinstance.cc @@ -302,7 +302,38 @@ SchemaRouterSession* SchemaRouter::newSession(MXS_SESSION* pSession) return rval; } -json_t* SchemaRouter::diagnostics() const +void SchemaRouter::diagnostics(DCB* dcb) +{ + double sescmd_pct = m_stats.n_sescmd != 0 ? + 100.0 * ((double)m_stats.n_sescmd / (double)m_stats.n_queries) : + 0.0; + + /** Session command statistics */ + dcb_printf(dcb, "\n\33[1;4mSession Commands\33[0m\n"); + dcb_printf(dcb, "Total number of queries: %d\n", + m_stats.n_queries); + dcb_printf(dcb, "Percentage of session commands: %.2f\n", + sescmd_pct); + dcb_printf(dcb, "Longest chain of stored session commands: %d\n", + m_stats.longest_sescmd); + dcb_printf(dcb, "Session command history limit exceeded: %d times\n", + m_stats.n_hist_exceeded); + + /** Session time statistics */ + + if (m_stats.sessions > 0) + { + dcb_printf(dcb, "\n\33[1;4mSession Time Statistics\33[0m\n"); + dcb_printf(dcb, "Longest session: %.2lf seconds\n", m_stats.ses_longest); + dcb_printf(dcb, "Shortest session: %.2lf seconds\n", m_stats.ses_shortest); + dcb_printf(dcb, "Average session length: %.2lf seconds\n", m_stats.ses_average); + } + dcb_printf(dcb, "Shard map cache hits: %d\n", m_stats.shmap_cache_hit); + dcb_printf(dcb, "Shard map cache misses: %d\n", m_stats.shmap_cache_miss); + dcb_printf(dcb, "\n"); +} + +json_t* SchemaRouter::diagnostics_json() const { double sescmd_pct = m_stats.n_sescmd != 0 ? 100.0 * ((double)m_stats.n_sescmd / (double)m_stats.n_queries) : diff --git a/server/modules/routing/schemarouter/schemarouterinstance.hh b/server/modules/routing/schemarouter/schemarouterinstance.hh index 62e1a152f..3b9856119 100644 --- a/server/modules/routing/schemarouter/schemarouterinstance.hh +++ b/server/modules/routing/schemarouter/schemarouterinstance.hh @@ -37,7 +37,8 @@ public: ~SchemaRouter(); static SchemaRouter* create(SERVICE* pService, char** pzOptions); SchemaRouterSession* newSession(MXS_SESSION* pSession); - json_t* diagnostics() const; + void diagnostics(DCB* pDcb); + json_t* diagnostics_json() const; uint64_t getCapabilities(); private: