diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-06-03 21:02:16 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-06-03 21:02:16 +0300 |
commit | cca955986efc0a7736ea0240fae2ce0694b16c5e (patch) | |
tree | 6f9c6c868e97b40ee25178724ee5435363278be8 /src | |
download | mysqlstat-cca955986efc0a7736ea0240fae2ce0694b16c5e.tar.gz mysqlstat-cca955986efc0a7736ea0240fae2ce0694b16c5e.tar.bz2 |
Initial commit
Diffstat (limited to 'src')
-rw-r--r-- | src/MYSQL-STAT-MIB.txt | 238 | ||||
-rw-r--r-- | src/Makefile.am | 59 | ||||
-rw-r--r-- | src/mysqlstat-mib.mib2c | 250 | ||||
-rw-r--r-- | src/mysqlstat.c | 304 | ||||
-rw-r--r-- | src/mysqlstat.h | 57 | ||||
-rw-r--r-- | src/mysqlstat.mib2c | 47 |
6 files changed, 955 insertions, 0 deletions
diff --git a/src/MYSQL-STAT-MIB.txt b/src/MYSQL-STAT-MIB.txt new file mode 100644 index 0000000..c9b4eb8 --- /dev/null +++ b/src/MYSQL-STAT-MIB.txt @@ -0,0 +1,238 @@ +MYSQL-STAT-MIB DEFINITIONS ::= BEGIN + +-- ************************************************************* +-- +-- MySQL statistics MIB +-- +-- ************************************************************* + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, enterprises, Counter64, + Counter32, Integer32 + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, DisplayString, TruthValue, TimeStamp + FROM SNMPv2-TC + OBJECT-GROUP, MODULE-COMPLIANCE + FROM SNMPv2-CONF; + +mysql MODULE-IDENTITY + LAST-UPDATED "201606031556Z" + ORGANIZATION "Gray Software" + CONTACT-INFO "Sergey Poznyakoff <gray@gnu.org>" + DESCRIPTION + "This MIB module defines objects for MySQL statistics." + REVISION "201606031556Z" + DESCRIPTION + "First revision." + ::= { enterprises 9163 101 } + +replication OBJECT IDENTIFIER ::= { mysql 1 } +replStatus OBJECT IDENTIFIER ::= { replication 1 } +replConfig OBJECT IDENTIFIER ::= { replication 2 } + +ThreadStatusString ::= TEXTUAL-CONVENTION + DISPLAY-HINT "128t" + STATUS current + DESCRIPTION "A string representing thread status." + SYNTAX OCTET STRING (SIZE (0..128)) + +-- Slave_IO_State: Waiting for master to send event +replSlaveIOState OBJECT-TYPE + SYNTAX ThreadStatusString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Describes what the thread is doing: trying to connect + to the master, waiting for events from the master, + reconnecting to the master, etc." + ::= { replStatus 1 } + +-- Master_Log_File: db1-bin-log.030151 +replMasterLogFile OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the master binary log file from which the + I/O thread is currently reading." + ::= { replStatus 2 } + +-- Read_Master_Log_Pos: 35721486 +replReadMasterLogPos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The position in the current master binary log file up + to which the I/O thread has read." + ::= { replStatus 3 } + +-- Relay_Log_File: relay-log.000094 +replRelayLogFile OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the relay log file from which the SQL + thread is currently reading and executing." + ::= { replStatus 4 } + +-- Relay_Log_Pos: 478170618 +replRelayLogPos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The position in the current relay log file up to + which the SQL thread has read and executed." + ::= { replStatus 5 } + +-- Relay_Master_Log_File: db1-bin-log.030068 +replRelayMasterLogFile OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the master binary log file containing the + most recent event executed by the SQL thread." + ::= { replStatus 6 } + +-- Slave_IO_Running: Yes +SlaveRunningState ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Represents slave I/O thread state." + SYNTAX INTEGER { yes(1), no(2), connecting(3) } + + +replSlaveIORunning OBJECT-TYPE + SYNTAX SlaveRunningState + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether the I/O thread is started and has connected + successfully to the master." + ::= { replStatus 7 } + +-- Slave_SQL_Running: Yes +replSlaveSQLRunning OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether the SQL thread is started." + ::= { replStatus 8 } + +-- Last_Errno: 0 +replLastSQLErrno OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The error code of the last error that caused the SQL + thread to stop." + ::= { replStatus 9 } + +SQLErrorString ::= TEXTUAL-CONVENTION + DISPLAY-HINT "1024t" + STATUS current + DESCRIPTION "A string representing SQL error." + SYNTAX OCTET STRING (SIZE (0..1024)) + +-- Last_Error: +replLastSQLError OBJECT-TYPE + SYNTAX SQLErrorString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The error message describing the last error that + caused the SQL thread to stop." + ::= { replStatus 10 } + +replLastIOErrno OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The error code of the last error that caused the IO + thread to stop." + ::= { replStatus 11 } + +replLastIOError OBJECT-TYPE + SYNTAX SQLErrorString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The error message describing the last error that + caused the IO thread to stop." + ::= { replStatus 12 } + +-- Exec_Master_Log_Pos: 478170471 +replExecMasterLogPos OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The position in the current master binary log file to + which the SQL thread has read and executed, marking + the start of the next transaction or event to be + processed." + ::= { replStatus 13 } + +-- Relay_Log_Space: 15820969237 +replRelayLogSpace OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total combined size of all existing relay log + files." + ::= { replStatus 14 } + +-- Seconds_Behind_Master: 77875 +replSecondsBehindMaster OBJECT-TYPE + SYNTAX TimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This field is an indication of how `late' the slave + is. Basically, it reflects the time difference in + seconds between the slave SQL thread and the slave + I/O thread." + ::= { replStatus 15 } + +-- TODO: replConfig +-- Master_Host: 172.26.16.233 +-- Master_User: repl +-- Master_Port: 3306 +-- Connect_Retry: 60 +-- Replicate_Do_DB: gha_ez,gha_storage +-- Replicate_Ignore_DB: gha_redesign_ez,gha_redesign_storage +-- Replicate_Do_Table: +-- Replicate_Ignore_Table: +-- Replicate_Wild_Do_Table: +-- Replicate_Wild_Ignore_Table: +-- Skip_Counter: 0 +-- Until_Condition: None +-- Until_Log_File: +-- Until_Log_Pos: 0 +-- Master_SSL_Allowed: No +-- Master_SSL_CA_File: +-- Master_SSL_CA_Path: +-- Master_SSL_Cert: +-- Master_SSL_Cipher: +-- Master_SSL_Key: +-- Master_SSL_Verify_Server_Cert: No + + +END + +-- Local variables: +-- eval: (add-hook 'write-file-hooks 'time-stamp) +-- time-stamp-start: "\\(LAST-UPDATED\\|REVISION\\) *\"" +-- time-stamp-end: "\"" +-- time-stamp-format: "%:y%02m%02d%02H%02MZ" +-- time-stamp-line-limit: 32 +-- time-stamp-count: 2 +-- end: + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..f3a2970 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,59 @@ +# This file is part of Mysqlstat -*- autoconf -*- +# Copyright (C) 2014-2016 Sergey Poznyakoff +# +# Mysqlstat is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# Mysqlstat is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mysqlstat. If not, see <http://www.gnu.org/licenses/>. + +dlmoddir=@DLMODDIR@ +dlmod_LTLIBRARIES = mysqlstat.la + +mysqlstat_la_SOURCES = \ + mysqlstat.c\ + mysqlstat.h\ + mysqlstat-mib.c + +BUILT_SOURCES = \ + mysqlstat-mib.c + +mysqlstat-mib.c: mysqlstat-mib.mib2c MYSQL-STAT-MIB.txt + +.mib2c.c: + MIBDIRS=${top_srcdir}/src:${NET_SNMP_MIBDIRS} MIBS="+MYSQL-STAT-MIB" \ + mib2c -c $< -f $@ mysql + +#NET_SNMP_INCLUDES = `$(NET_SNMP_CONFIG) --cflags` +#NET_SNMP_INCLUDES = +NET_SNMP_LIBS = `$(NET_SNMP_CONFIG) --libs` +NET_SNMP_EXLIBS = `$(NET_SNMP_CONFIG) --external-libs` +NET_SNMP_MIBDIRS = `net-snmp-config --mibdirs` + +AM_LDFLAGS = \ + -module \ + -export-dynamic\ + -avoid-version \ + -rpath '$(dlmoddir)'\ + ${MYSQL_LIBS}\ + $(NET_SNMP_LIBS)\ + $(NET_SNMP_EXLIBS) + +AM_CPPFLAGS=\ + -I. \ + ${MYSQL_CFLAGS}\ + -DCONFDIR=\"$(CONFDIR)\" + +mibdir=@MIBDIR@ +mib_DATA = MYSQL-STAT-MIB.txt + +#dist_man_MANS = mysqlstat.8 + +EXTRA_DIST = MYSQL-STAT-MIB.txt mysqlstat-mib.mib2c diff --git a/src/mysqlstat-mib.mib2c b/src/mysqlstat-mib.mib2c new file mode 100644 index 0000000..fb6e80b --- /dev/null +++ b/src/mysqlstat-mib.mib2c @@ -0,0 +1,250 @@ +# This file is part of Mysqlstat -*- autoconf -*- +# Copyright (C) 2014-2016 Sergey Poznyakoff +# +# Mysqlstat is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# Mysqlstat is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mysqlstat. If not, see <http://www.gnu.org/licenses/>. + +@define ROCOM@ +/* Local variables: + buffer-read-only: t + End: + vi: set ro: +*/ +@enddefine@ +@startperl@ +$vars{'mysqlstat_translate_table'} = { + replSlaveIOState => [ + 'MYSQLSTAT_CACHE_REPL', 'Slave_IO_State' ], + replMasterLogFile => [ + 'MYSQLSTAT_CACHE_REPL', 'Master_Log_File' ], + replReadMasterLogPos => [ + 'MYSQLSTAT_CACHE_REPL', 'Read_Master_Log_Pos' ], + replRelayLogFile => [ + 'MYSQLSTAT_CACHE_REPL', 'Relay_Log_File' ], + replRelayLogPos => [ + 'MYSQLSTAT_CACHE_REPL', 'Relay_Log_Pos' ], + replRelayMasterLogFile => [ + 'MYSQLSTAT_CACHE_REPL', 'Relay_Master_Log_File' ], + replSlaveIORunning => [ + 'MYSQLSTAT_CACHE_REPL', 'Slave_IO_Running' ], + replSlaveSQLRunning => [ + 'MYSQLSTAT_CACHE_REPL', 'Slave_SQL_Running' ], + replLastSQLErrno => [ + 'MYSQLSTAT_CACHE_REPL', 'Last_SQL_Errno' ], + replLastSQLError => [ + 'MYSQLSTAT_CACHE_REPL', 'Last_SQL_Error' ], + replLastIOErrno => [ + 'MYSQLSTAT_CACHE_REPL', 'Last_IO_Errno' ], + replLastIOError => [ + 'MYSQLSTAT_CACHE_REPL', 'Last_IO_Error' ], + replExecMasterLogPos => [ + 'MYSQLSTAT_CACHE_REPL', 'Exec_Master_Log_Pos' ], + replRelayLogSpace => [ + 'MYSQLSTAT_CACHE_REPL', 'Relay_Log_Space' ], + replSecondsBehindMaster => [ + 'MYSQLSTAT_CACHE_REPL', 'Seconds_Behind_Master' ] +}; + +$vars{'mysqlstat_translate'} = sub { + my ($name) = @_; + + my $r = $vars{'mysqlstat_translate_table'}->{$name}; + if (!defined($r)) { + print STDERR "no translation for $name!\n"; + exit(1); + } + + $vars{'mysqlstat_id'} = $r->[0]; + $vars{'mysqlstat_name'} = $r->[1]; +# $vars{'mysqlstat_type'} = $r->[2]; + return 0; +}; + +$vars{'modulename'} = $vars{'name'}; +$vars{'modulename'} =~ s#.*/##; +$vars{'modulename'} =~ s/\.c$//; +#print "$vars{'modulename'}\n"; + +0; +@endperl@ +@open ${name}@ +/* THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. */ + +#include "mysqlstat.h" + +/* Variable handlers. + + An instance handler only hands us one request at a time, unwrapping + any eventual GETNEXT requests. +*/ + +@foreach $i scalar@ + @startperl@ + &{$vars{'mysqlstat_translate'}}($vars{'i'}); + @endperl@ + +static int +handle_$i(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + @if $i.settable@ + int ret; + @end@ + char const *val = mysqlstat_get($varnish_id, "$varnish_name"); + + if (!val) + return SNMP_ERR_NOSUCHNAME; + + switch(reqinfo->mode) { + case MODE_GET: + @if $i.type eq 'ASN_COUNTER64'@ + { + struct counter64 ctr; + uint64_t n = strtoull(val, NULL, 10); + ctr.high = n >> 32; + ctr.low = n & 0xffffffff; + snmp_set_var_typed_value(requests->requestvb, $i.type, + &ctr, + sizeof(ctr)); + } + @elsif $i.type eq 'ASN_OCTET_STR'@ + snmp_set_var_typed_value(requests->requestvb, $i.type, + val, strlen(val)); + break; + @elsif $i.type eq 'ASN_COUNTER32'@ + { + uint32_t n = strtoul(val, NULL, 10); + snmp_set_var_typed_value(requests->requestvb, $i.type, + &n, + sizeof(n)); + } + @elsif $i.type eq 'ASN_INTEGER32'@ + { + uint32_t n = strtoul(val, NULL, 10); + snmp_set_var_typed_value(requests->requestvb, $i.type, + &n, + sizeof(n)); + } + @else@ + @printf "unrecognized type %s for %s" $i.type $i@ + @end@ + break; + + @if $i.settable@ + /* + * SET REQUEST + * + * multiple states in the transaction. See: + * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg + */ + case MODE_SET_RESERVE1: + /* or you could use netsnmp_check_vb_type_and_size instead */ + ret = netsnmp_check_vb_type(requests->requestvb, $i.type); + if (ret != SNMP_ERR_NOERROR) + netsnmp_set_request_error(reqinfo, requests, ret); + break; + + case MODE_SET_RESERVE2: + @if $mysqlstat_set_reserve2 ne ''@ + if ($mysqlstat_set_reserve2 (reqinfo, requests, vd)) { + netsnmp_set_request_error(reqinfo, requests, + SNMP_ERR_RESOURCEUNAVAILABLE); + } + @end@ + break; + + case MODE_SET_FREE: + @if $mysqlstat_set_free ne ''@ + # Free resources allocated in RESERVE1 and/or + # RESERVE2. Something failed somewhere, and the states + # below won't be called. + $varnish_set_free(reqinfo, requests, vd); + @end@ + break; + + case MODE_SET_ACTION: + @if $mysqlstat_set_action ne ''@ + ret = $mysqlstat_set_action(reqinfo, requests, vd); + if (ret != SNMP_ERR_NOERROR) + netsnmp_set_request_error(reqinfo, requests, ret); + @end@ + break; + + case MODE_SET_COMMIT: + @if $mysqlstat_set_commit ne ''@ + # delete temporary storage + if ($mysqlstat_set_commit(reqinfo, requests, vd)) + netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_COMMITFAILED); + @end@ + break; + + case MODE_SET_UNDO: + @if $mysqlstat_set_undo ne ''@ + # UNDO and return to previous value for the object + if ($mysqlstat_set_undo(reqinfo, requests, vd)) + netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); + @end@ + break; + @end@ + + default: + /* we should never get here, so this is a really bad error */ + snmp_log(LOG_ERR, "unknown mode (%d) in handle_${i}\n", reqinfo->mode ); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} +@end@ + +/** Initializes the $name module */ +void +init_$modulename(void) +{ + @foreach $i scalar@ + @startperl@ + &{$vars{'mysqlstat_translate'}}($vars{'i'}); + @endperl@ +$varnish_if + const oid ${i}_oid[] = { $i.commaoid }; +$varnish_endif + @end@ + + DEBUGMSGTL(("$modulename", "Initializing\n")); + + @foreach $i scalar@ + @startperl@ + &{$vars{'mysqlstat_translate'}}($vars{'i'}); + @endperl@ + netsnmp_register_scalar( + netsnmp_create_handler_registration("$i", handle_$i, + ${i}_oid, OID_LENGTH(${i}_oid), + @if !$i.settable@ + HANDLER_CAN_RONLY + @end@ + @if $i.settable@ + HANDLER_CAN_RWRITE + @end@ + )); +} + +void +deinit_$modulename(void) +{ + /* Nothing */ +} +@calldefine ROCOM@ + + diff --git a/src/mysqlstat.c b/src/mysqlstat.c new file mode 100644 index 0000000..1ce7014 --- /dev/null +++ b/src/mysqlstat.c @@ -0,0 +1,304 @@ +/* This file is part of Mysqlstat -*- autoconf -*- + * Copyright (C) 2014-2016 Sergey Poznyakoff + * + * Mysqlstat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * Mysqlstat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mysqlstat. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <mysqlstat.c> +#include <mysql.c> + +static char *config_file = CONFDIR "/mysqlstat.cnf"; + +struct mysqlstat_connection { + MYSQL mysql; +}; + +mysqlstat_connection_t +mysqlstat_connect(void) +{ + struct mysqlstat_connection *conn; + my_bool t = 1; + + conn = xcalloc(sizeof(*conn)); + mysql_init(&conn->mysql); + if (access(config_file, F_OK) == 0) + mysql_options(&conn->mysql, MYSQL_READ_DEFAULT_FILE, + config_file); + mysql_options(&conn->mysql, MYSQL_READ_DEFAULT_GROUP, "mysqlstat"); + mysql_options(&conn->mysql, MYSQL_OPT_RECONNECT, &t); + if (!mysql_real_connect(&conn->mysql, NULL, NULL, NULL, NULL, 0, + NULL, 0)) { + snmp_log(LOG_ERR, "can't connect to MySQL: %s", + mysql_error(&conn->mysql)); + free(conn); + conn = NULL; + } + return conn; +} + +void +mysqlstat_disconnect(mysqlstat_connection_t *conn) +{ + if (!conn) + return; + mysql_close(&conn->mysql); + free(conn); +} + +struct syment { + char *name; + char *value; +}; + +static unsigned int hash_size[] = { + 7, 17, 37, 101, 229, 487, 1009, 2039, 4091, 8191, 16411 +}; + +/* |max_rehash| keeps the number of entries in |hash_size| table. */ +static unsigned int max_rehash = sizeof(hash_size) / sizeof(hash_size[0]); + +struct hashtab { + uint32_t hc; + struct syment *tab; +}; + +static void +syment_free(struct syment *ent) +{ + free(ent->name); + ent->name = NULL; + free(ent->value); + ent->value = NULL; +} + +static int +syment_matches(struct syment *ent, char const *name) +{ + if (!syment->name) + return 0; + return strcmp(ent->name, name) == 0; +} + +static uint32_t +hash_string(const char *name, uint32_t hashsize) +{ + unsigned i; + + for (i = 0; *name; name++) { + i <<= 1; + i ^= *(unsigned char*) name; + } + return i % hashsize; +} + +static uint32_t +find_insert_pos(struct hashtab *ht, struct syment *ent) +{ + uint32_t i; + uint32_t pos = hash_string(ent->name, hash_size[ht->hc]); + + for (i = pos; ht->tab[i].name; ) { + i = (i + 1) % hash_size[ht->hc]; + if (i == pos) + /* FIXME: Error message? */ + abort(); + } + return i; +} + +static void +rehash(struct hashtab *ht) +{ + struct syment *oldtab = ht->tab; + struct syment *newtab; + uint32_t i, n; + + assert(ht->hc + 1 < max_rehash); + n = hash_size[ht->hc]; + ++ht->hc; + newtab = xcalloc(hash_size[ht->hc], sizeof(newtab[0])); + for (i = 0; i < n; i++) { + if (ent->name) + newtab[find_insert_pos(ht, &oldtab[i])] = oldtab[i]; + } + free(oldtab); +} + +static void +hashtab_remove(struct hashtab *ht, char const *name) +{ + uint32_t int pos, i, j, r; + + pos = hash_string(name, hash_size[ht->hc]); + for (i = pos; ht->tab[i].name;) { + if (syment_matches(&ht->tab[i], name)) + break; + i = (i + 1) % hash_size[ht->hc]; + if (i == pos) + return;// ENOENT + } + + syment_free(ht->tab[i]); + + for (;;) { + st->tab[i] = NULL; + j = i; + + do { + i = (i + 1) % hash_size[ht->hc]; + if (!st->tab[i].name) + return; + r = hash_string(ht->tab[i].name, hash_size[ht->hc]); + } while ((j < r && r <= i) + || (i < j && j < r) || (r <= i && i < j)); + st->tab[j] = st->tab[i]; + } +} + +static char const * +hashtab_lookup(struct hashtab *ht, char const *name) +{ + uint32_t pos; + + pos = hash_string(name, hash_size[ht->hc]); + for (i = pos; ht->tab[i].name;) { + if (syment_matches(&ht->tab[i], name)) + return ht->tab[i].name; + i = (i + 1) % hash_size[ht->hc]; + if (i == pos) + break; + } + return NULL; +} + +static void +hashtab_install(struct hashtab *ht, char const *name, char const *value) +{ + uint32_t pos; + struct syment *ent; + + pos = hash_string(name, hash_size[ht->hc]); + for (i = pos; ht->tab[i].name;) { + if (syment_matches(&ht->tab[i], name)) { + free(ht->tab[i].value); + ht->tab[i].value = xtsrdup(value); + return; + } + i = (i + 1) % hash_size[ht->hc]; + if (i == pos) { + rehash(ht); + i = pos = hash_string(name, hash_size[ht->hc]); + } + } + + ht->tab[i].name = xtsrdup(name); + ht->tab[i].value = xtsrdup(value); +} + +void +hashtab_clear(struct hashtab *ht) +{ + unsigned i, hs; + + hs = hash_size[st->hash_num]; + for (i = 0; i < hs; i++) { + syment_free(&ht->tab[i]); + } +} + +static struct hashtab * +hashtab_create(void) +{ + struct hashtab *ht = xmalloc(sizeof(*ht)); + ht->hc = 0; + ht->tab = xcalloc(hash_size[ht->hc], sizeof(newtab[0])); + return ht; +} + +struct mysqlstat_cache { + void (*populate) (struch hashtab *); + struch hashtab *ht; + time_t ts; +}; + +static unsigned cache_timeout = CACHE_TIMEOUT; + +static char const * +mysqlstat_cache_get(struct mysqlstat_cache *cache, char const *name) +{ + time_t now = time(NULL); + struct syment *ent; + + if (!cache->ht) + cache->ht = hashtab_create(); + if (now - cache->ts > cache_timeout) { + hashtab_clear(cache->ht); + cache->populate(cache->ht); + cache->ts = now; + } + return hashtab_lookup(cache->ht, name); +} + +static void +populate_repl(struch hashtab *ht) +{ + mysqlstat_connection_t conn; + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL_FIELD *fields; + unsigned int num_fields, i; + + conn = mysqlstat_connect(); + if (!conn) + return; + + if (mysql_query(&conn->mysql, "SHOW SLAVE STATUS")) { + snmp_log(LOG_ERR, "can't get slave status: %s", + mysql_error(&conn->mysql)); + return; + } + + res = mysql_store_result(&conn->mysql); + if (mysql_num_rows(res) < 1) { + snmp_log(LOG_INFO, "empty slave status"); + return; + } + + num_fields = mysql_num_fields(res); + fields = mysql_fetch_fields(res); + row = mysql_fetch_row(res); + for (i = 0; i < num_fields; i++) + hashtab_install(ht, fields[i].name, row[i] ? row[i] : NULL); + mysql_free_result(res); + mysqlstat_disconnect(conn); +} + +static struct mysqlstat_cache cache[MYSQLSTAT_MAX_CACHE] = { + [MYSQLSTAT_CACHE_REPL] = { populate_repl } +}; + +char const * +mysqlstat_get(int id, char const *name) +{ + return mysqlstat_cache_get(cache + i, name); +} + + + + + + + + + diff --git a/src/mysqlstat.h b/src/mysqlstat.h new file mode 100644 index 0000000..1fc724e --- /dev/null +++ b/src/mysqlstat.h @@ -0,0 +1,57 @@ +/* This file is part of Mysqlstat -*- autoconf -*- + * Copyright (C) 2014-2016 Sergey Poznyakoff + * + * Mysqlstat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * Mysqlstat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mysqlstat. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#define CACHE_TIMEOUT 10 + +enum { + MYSQLSTAT_CACHE_REPL, + MYSQLSTAT_MAX_CACHE +}; + +typedef struct mysqlstat_connection *mysqlstat_connection_t; + +struct repl_stat { + char *replMasterLogFile; + uint32_t replReadMasterLogPos; + char *replRelayLogFile; + uint32_t replRelayLogPos; + char *replRelayMasterLogFile; + int replSlaveIORunning; + int replSlaveSQLRunning; + int replLastSQLErrno; + char *replLastSQLError; + int replLastIOErrno; + char *replLastIOError; + uint32_t replExecMasterLogPos; + uint64_t replRelayLogSpace; + uint32_t replSecondsBehindMaster; +}; + +mysqlstat_connection_t mysqlstat_connect(void); +void mysqlstat_disconnect(mysqlstat_connection_t); + +char const *mysqlstat_get(int id, char const *name); diff --git a/src/mysqlstat.mib2c b/src/mysqlstat.mib2c new file mode 100644 index 0000000..0b2bd50 --- /dev/null +++ b/src/mysqlstat.mib2c @@ -0,0 +1,47 @@ +# This file is part of Mysqlstat -*- autoconf -*- +# Copyright (C) 2014-2016 Sergey Poznyakoff +# +# Mysqlstat is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# Mysqlstat is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mysqlstat. If not, see <http://www.gnu.org/licenses/>. + +@define ROCOM@ +/* Local variables: + buffer-read-only: t + End: + vi: set ro: +*/ +@enddefine@ +@startperl@ +// FIXME: translation table + +$vars{'modulename'} = $vars{'name'}; +$vars{'modulename'} =~ s#.*/##; +$vars{'modulename'} =~ s/\.c$//; +#print "$vars{'modulename'}\n"; + +0; +@endperl@ +@open ${modulename}.h@ +/* THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. */ +#include <config.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> + +// FIXME +@open ${name}@ +/* THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. */ + +#include "mysqlstat.h" + |