diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-06-07 08:01:46 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-06-07 08:01:46 +0300 |
commit | 757b835af8984c1fa796aec1789b484bd307bb8a (patch) | |
tree | 7f37eec457262277ff2fe856eb2907155fded780 | |
parent | ec36698ad30b99a05104952f011cf471faf83e56 (diff) | |
download | mysqlstat-757b835af8984c1fa796aec1789b484bd307bb8a.tar.gz mysqlstat-757b835af8984c1fa796aec1789b484bd307bb8a.tar.bz2 |
Keep MySQL connection open as long as possible. Implement new OIDs.
* src/MYSQL-STAT-MIB.txt: New OIDs: processTotalCount,
processActiveCount, and processSlaveCount
* src/mysqlstat.c (mysqlstat_connect): Keep connection open.
(mysqlstat_disconnect): Remove.
(get_process_list, process_first, process_next): New functions.
Keep a cached list of processes and iterate through it.
All functions updated.
(process_total_count,process_active_count)
(process_slave_count): New functions.
* src/mysqlstat.h (process_total_count,process_active_count)
(process_slave_count): New protos.
* src/mysqlstat_mib.mib2c (handle_$i): Update.
-rw-r--r-- | src/MYSQL-STAT-MIB.txt | 127 | ||||
-rw-r--r-- | src/mysqlstat.c | 194 | ||||
-rw-r--r-- | src/mysqlstat.h | 27 | ||||
-rw-r--r-- | src/mysqlstat_mib.mib2c | 114 |
4 files changed, 191 insertions, 271 deletions
diff --git a/src/MYSQL-STAT-MIB.txt b/src/MYSQL-STAT-MIB.txt index 8fbc0e6..3c05db2 100644 --- a/src/MYSQL-STAT-MIB.txt +++ b/src/MYSQL-STAT-MIB.txt @@ -18,12 +18,12 @@ IMPORTS FROM INET-ADDRESS-MIB; mysql MODULE-IDENTITY - LAST-UPDATED "201606061638Z" + LAST-UPDATED "201606070800Z" ORGANIZATION "Gray Software" CONTACT-INFO "Sergey Poznyakoff <gray@gnu.org>" DESCRIPTION "This MIB module defines objects for MySQL statistics." - REVISION "201606061638Z" + REVISION "201606070800Z" DESCRIPTION "First revision." ::= { enterprises 9163 101 } @@ -461,102 +461,6 @@ replMasterSSLVerifyServerCert OBJECT-TYPE ::= { replSlaveStatusEntry 38 } -- --- Table of Replication Slave Servers --- - --- replSlaveCount OBJECT-TYPE --- SYNTAX Counter32 --- MAX-ACCESS read-only --- STATUS current --- DESCRIPTION --- "Number of active replication slaves." --- ::= { replSlave 1 } - --- replSlaveTable OBJECT-TYPE --- SYNTAX SEQUENCE OF ReplSlaveEntry --- MAX-ACCESS not-accessible --- STATUS current --- DESCRIPTION --- "A table of active replication slaves." --- ::= { replSlave 2 } - --- replSlaveEntry OBJECT-TYPE --- SYNTAX ReplSlaveEntry --- MAX-ACCESS not-accessible --- STATUS current --- DESCRIPTION --- "An entry (conceptual row) describing a replication --- slave server." --- INDEX { replSlaveIndex } --- ::= { replSlaveTable 1 } - --- ReplSlaveEntry ::= SEQUENCE { --- replSlaveIndex Integer32, --- replSlaveHost DisplayString, --- replSlaveUser DisplayString, --- replSlaveCommand DisplayString, --- replSlaveState DisplayString, --- replSlaveTime TimeStamp, --- replSlaveInfo DisplayString --- } - --- replSlaveIndex OBJECT-TYPE --- SYNTAX Integer32 (0..65535) --- MAX-ACCESS not-accessible --- STATUS current --- DESCRIPTION --- "A number uniquely identifying each slave server." --- ::= { replSlaveEntry 1 } - --- replSlaveHost OBJECT-TYPE --- SYNTAX DisplayString --- MAX-ACCESS read-only --- STATUS current --- DESCRIPTION --- "Hostname of the server." --- ::= { replSlaveEntry 2 } - --- replSlaveUser OBJECT-TYPE --- SYNTAX DisplayString --- MAX-ACCESS read-only --- STATUS current --- DESCRIPTION --- "User name used by that server." --- ::= { replSlaveEntry 3 } - --- replSlaveCommand OBJECT-TYPE --- SYNTAX DisplayString --- MAX-ACCESS read-only --- STATUS current --- DESCRIPTION --- "Command being run." --- ::= { replSlaveEntry 4 } - --- replSlaveState OBJECT-TYPE --- SYNTAX DisplayString --- MAX-ACCESS read-only --- STATUS current --- DESCRIPTION --- "State of the connection." --- ::= { replSlaveEntry 5 } - --- replSlaveTime OBJECT-TYPE --- SYNTAX TimeStamp --- MAX-ACCESS read-only --- STATUS current --- DESCRIPTION --- "Timestamp of the last status change." --- ::= { replSlaveEntry 6 } - --- replSlaveInfo OBJECT-TYPE --- SYNTAX DisplayString --- MAX-ACCESS read-only --- STATUS current --- DESCRIPTION --- "Additional info about the connection." --- ::= { replSlaveEntry 7 } - --- -- Process List -- @@ -566,7 +470,7 @@ processListTable OBJECT-TYPE STATUS current DESCRIPTION "A table of active threads." - ::= { processList 2 } + ::= { processList 1 } processListEntry OBJECT-TYPE SYNTAX ProcessListEntry @@ -660,6 +564,31 @@ processInfo OBJECT-TYPE DESCRIPTION "Information about the process." ::= { processListEntry 9 } + +processTotalCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of processes (threads)." + ::= { processList 2 } + +processActiveCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of active processes (threads)." + ::= { processList 3 } + +processSlaveCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of replication slaves" + ::= { processList 4 } + END -- Local variables: diff --git a/src/mysqlstat.c b/src/mysqlstat.c index 938439a..2ffd0dd 100644 --- a/src/mysqlstat.c +++ b/src/mysqlstat.c @@ -54,33 +54,28 @@ xstrdup(char const *s) mysqlstat_connection_t mysqlstat_connect(void) { - struct mysqlstat_connection *conn; + static struct mysqlstat_connection *conn; my_bool t = 1; + if (!conn) { conn = xcalloc(1, 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_READ_DEFAULT_GROUP, "mysqlstat"); mysql_options(&conn->mysql, MYSQL_OPT_RECONNECT, &t); - if (!mysql_real_connect(&conn->mysql, NULL, NULL, NULL, NULL, 0, + if (!mysql_real_connect(&conn->mysql, + NULL, NULL, NULL, NULL, 0, NULL, 0)) { snmp_log(LOG_ERR, "can't connect to MySQL: %s\n", 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); + return conn; } unsigned mysqlstat_cache_timeout = CACHE_TIMEOUT; @@ -102,6 +97,97 @@ unsigned mysqlstat_cache_timeout = CACHE_TIMEOUT; #define STREQ(pat,str) (strcmp(#pat, str) == 0) +struct process_list { + time_t ts; + MYSQL_RES *res; + uint32_t total; + uint32_t active; + uint32_t slaves; + uint32_t itr; +}; + +enum { + FI_processID, + FI_processUser, + FI_processHost, + FI_processDatabase, + FI_processCommand, + FI_processTime, + FI_processState, + FI_processInfo +}; + +static int +get_process_list(struct process_list **p) +{ + static struct process_list plist; + time_t now; + + now = time(NULL); + if (!plist.res || now - plist.ts >= mysqlstat_cache_timeout) { + mysqlstat_connection_t conn; + unsigned i; + + if (plist.res) { + mysql_free_result(plist.res); + plist.res = NULL; + plist.total = plist.active = plist.slaves = 0; + } + DEBUGMSGTL(("mysqlstat", "Getting process list\n")); + + conn = mysqlstat_connect(); + if (!conn) + return SNMP_ERR_GENERR; + + if (mysql_query(&conn->mysql, "SHOW PROCESSLIST")) { + snmp_log(LOG_ERR, "can't get slave process list: %s\n", + mysql_error(&conn->mysql)); + return SNMP_ERR_NOSUCHNAME; + } + plist.res = mysql_store_result(&conn->mysql); + plist.ts = now; + + plist.total = mysql_num_rows(plist.res); + for (i = 0; i < plist.total; i++) { + MYSQL_ROW row; + + mysql_data_seek(plist.res, i); + row = mysql_fetch_row(plist.res); + if (!row[FI_processState] + || STREQ(Sleep, row[FI_processState])) + continue; + if (row[FI_processCommand] + && strcmp(row[FI_processCommand], "Binlog Dump") == 0) + plist.slaves++; + else + plist.active++; + } + } + *p = &plist; + return 0; +} + +MYSQL_ROW +process_next(struct process_list *p) +{ + MYSQL_ROW row; + if (p->itr >= p->total) + return NULL; + mysql_data_seek(p->res, p->itr); + ++p->itr; + return mysql_fetch_row(p->res); +} + +MYSQL_ROW +process_first(struct process_list **state) +{ + struct process_list *p; + if (get_process_list(&p)) + return NULL; + p->itr = 0; + *state = p; + return process_next(p); +} static long val_Slave_IO_Running(char const *val) @@ -224,13 +310,12 @@ replSlaveStatusTable_load(netsnmp_cache *cache, void *vmagic) if (mysql_query(&conn->mysql, "SHOW SLAVE STATUS")) { snmp_log(LOG_ERR, "can't get slave status: %s\n", mysql_error(&conn->mysql)); - mysqlstat_disconnect(conn); return SNMP_ERR_NOSUCHNAME; } res = mysql_store_result(&conn->mysql); if (mysql_num_rows(res) < 1) { - snmp_log(LOG_INFO, "empty slave status\n"); + /* snmp_log(LOG_INFO, "empty slave status\n"); */ return 0; } @@ -240,14 +325,12 @@ replSlaveStatusTable_load(netsnmp_cache *cache, void *vmagic) ent = SNMP_MALLOC_TYPEDEF(struct replSlaveStatusTable_entry); if (!ent) { - mysqlstat_disconnect(conn); return SNMP_ERR_GENERR; } data_row = netsnmp_tdata_create_row(); if (!data_row) { SNMP_FREE(ent); - mysqlstat_disconnect(conn); return SNMP_ERR_GENERR; } data_row->data = ent; @@ -262,7 +345,6 @@ replSlaveStatusTable_load(netsnmp_cache *cache, void *vmagic) store_slave_status_row(ent, fields[i].name, row[i]); mysql_free_result(res); - mysqlstat_disconnect(conn); return 0; } @@ -295,18 +377,6 @@ replSlaveStatusTable_entry_free(void *data) free(ent->replMasterSSLKey); } - -enum { - FI_processID, - FI_processUser, - FI_processHost, - FI_processDatabase, - FI_processCommand, - FI_processTime, - FI_processState, - FI_processInfo -}; - static void process_list_add(netsnmp_tdata *table_data, long idx, MYSQL_ROW mysql_row) { @@ -327,8 +397,13 @@ process_list_add(netsnmp_tdata *table_data, long idx, MYSQL_ROW mysql_row) ent->processIndex = idx; if (mysql_row[FI_processID]) ent->processID = strtol(mysql_row[FI_processID], NULL, 10); + ASSIGN_ROW(ent, processUser, mysql_row); - ASSIGN_ROW(ent, processHost, mysql_row); + + ent->processHost_len = strcspn(mysql_row[FI_processHost], ":"); + ent->processHost = xmalloc(ent->processHost_len); + memcpy(ent->processHost, mysql_row[FI_processHost], ent->processHost_len); + ASSIGN_ROW(ent, processDatabase, mysql_row); ASSIGN_ROW(ent, processCommand, mysql_row); if (mysql_row[FI_processTime]) @@ -346,39 +421,14 @@ process_list_add(netsnmp_tdata *table_data, long idx, MYSQL_ROW mysql_row) int processListTable_load(netsnmp_cache *cache, void *vmagic) { - mysqlstat_connection_t conn; - MYSQL_RES *res; - unsigned int num_rows, i; + struct process_list *p; netsnmp_tdata *table = (netsnmp_tdata *) vmagic; - - DEBUGMSGTL(("mysqlstat", "Getting process list\n")); - - conn = mysqlstat_connect(); - if (!conn) - return SNMP_ERR_GENERR; - - if (mysql_query(&conn->mysql, "SHOW PROCESSLIST")) { - snmp_log(LOG_ERR, "can't get slave process list: %s\n", - mysql_error(&conn->mysql)); - mysqlstat_disconnect(conn); - return SNMP_ERR_NOSUCHNAME; - } - - res = mysql_store_result(&conn->mysql); - num_rows = mysql_num_rows(res); - - for (i = 0; i < num_rows; i++) { MYSQL_ROW row; + uint32_t i; - mysql_data_seek(res, i); - row = mysql_fetch_row(res); - + for (row = process_first(&p), i = 0; row; row = process_next(p), i++) { process_list_add(table, i, row); } - - mysql_free_result(res); - mysqlstat_disconnect(conn); - return 0; } @@ -393,6 +443,34 @@ processListTable_entry_free(void *data) free(ent->processInfo); } +uint32_t +process_total_count(void) +{ + struct process_list *p; + if (get_process_list(&p)) + return 0; + return p->total; +} + +uint32_t +process_active_count(void) +{ + struct process_list *p; + if (get_process_list(&p)) + return 0; + return p->active; +} + +uint32_t +process_slave_count(void) +{ + struct process_list *p; + if (get_process_list(&p)) + return 0; + return p->slaves; +} + + #if 0 unsigned replSlaveTable_timeout = CACHE_TIMEOUT; diff --git a/src/mysqlstat.h b/src/mysqlstat.h index 1fc724e..f4bf137 100644 --- a/src/mysqlstat.h +++ b/src/mysqlstat.h @@ -27,31 +27,12 @@ #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); +uint32_t process_total_count(void); +uint32_t process_active_count(void); +uint32_t process_slave_count(void); + diff --git a/src/mysqlstat_mib.mib2c b/src/mysqlstat_mib.mib2c index 7f00d9b..733f977 100644 --- a/src/mysqlstat_mib.mib2c +++ b/src/mysqlstat_mib.mib2c @@ -23,81 +23,9 @@ @enddefine@ @startperl@ $vars{'mysqlstat_translate_table'} = { - replSlaveIOState => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Slave_IO_State")}, - replMasterLogFile => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_Log_File")}, - replReadMasterLogPos => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Read_Master_Log_Pos")}, - replRelayLogFile => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Relay_Log_File")}, - replRelayLogPos => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Relay_Log_Pos")}, - replRelayMasterLogFile => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Relay_Master_Log_File")}, - replSlaveIORunning => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Slave_IO_Running")}, - replSlaveSQLRunning => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Slave_SQL_Running")}, - replLastSQLErrno => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Last_SQL_Errno")}, - replLastSQLError => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Last_SQL_Error")}, - replLastIOErrno => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Last_IO_Errno")}, - replLastIOError => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Last_IO_Error")}, - replExecMasterLogPos => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Exec_Master_Log_Pos")}, - replRelayLogSpace => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Relay_Log_Space")}, - replSecondsBehindMaster => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Seconds_Behind_Master")}, - - replMasterHost => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_Host")}, - replMasterUser => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_User")}, - replMasterPort => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_Port")}, - replConnectRetry => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Connect_Retry")}, - replReplicateDoDB => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Replicate_Do_DB")}, - replReplicateIgnoreDB => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Replicate_Ignore_DB")}, - replReplicateDoTable => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Replicate_Do_Table")}, - replReplicateIgnoreTable => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Replicate_Ignore_Table")}, - replReplicateWildDoTable => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Replicate_Wild_Do_Table")}, - replReplicateWildIgnoreTable => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Replicate_Wild_Ignore_Table")}, - replSkipCounter => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Skip_Counter")}, - replUntilCondition => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Until_Condition")}, - replUntilLogFile => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Until_Log_File")}, - replUntilLogPos => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Until_Log_Pos")}, - replMasterServerId => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_Server_Id")}, - replMasterSSLAllowed => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_SSL_Allowed")}, - replMasterSSLCAFile => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_SSL_CA_File")}, - replMasterSSLCAPath => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_SSL_CA_Path")}, - replMasterSSLCert => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_SSL_Cert")}, - replMasterSSLCipher => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_SSL_Cipher")}, - replMasterSSLKey => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_SSL_Key")}, - replMasterSSLVerifyServerCert => - q{mysqlstat_get(MYSQLSTAT_CACHE_REPL, "Master_SSL_Verify_Server_Cert")} + processTotalCount => q{process_total_count()}, + processActiveCount => q{process_active_count()}, + processSlaveCount => q{process_slave_count()} }; $vars{'mysqlstat_translate'} = sub { @@ -148,19 +76,26 @@ handle_$i(netsnmp_mib_handler *handler, @if $i.settable@ int ret; @end@ - char const *val = $mysqlstat_get; - - if (!val) - return SNMP_ERR_NOSUCHNAME; + @if $i.type eq 'ASN_OCTET_STR'@ + @eval $mysqlstat_type = q{char const *};@ + @elsif $i.type eq 'ASN_COUNTER64'@ + @eval $mysqlstat_type = q{uint64_t};@ + @elsif $i.type eq 'ASN_COUNTER'@ + @eval $mysqlstat_type = q{uint32_t};@ + @elsif $i.type eq 'ASN_INTEGER'@ + @eval $mysqlstat_type = q{uint32_t};@ + @elsif $i.type eq 'ASN_TIMETICKS'@ + @eval $mysqlstat_type = q{uint32_t};@ + @end@ + $mysqlstat_type val = $mysqlstat_get; 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; + ctr.high = val >> 32; + ctr.low = val & 0xffffffff; snmp_set_var_typed_value(requests->requestvb, $i.type, &ctr, sizeof(ctr)); @@ -172,24 +107,21 @@ handle_$i(netsnmp_mib_handler *handler, } @elsif $i.type eq 'ASN_COUNTER'@ { - uint32_t n = strtoul(val, NULL, 10); snmp_set_var_typed_value(requests->requestvb, $i.type, - &n, - sizeof(n)); + &val, + sizeof(val)); } @elsif $i.type eq 'ASN_INTEGER'@ { - uint32_t n = strtoul(val, NULL, 10); snmp_set_var_typed_value(requests->requestvb, $i.type, - &n, - sizeof(n)); + &val, + sizeof(val)); } @elsif $i.type eq 'ASN_TIMETICKS'@ { - uint32_t n = strtoul(val, NULL, 10); snmp_set_var_typed_value(requests->requestvb, $i.type, - &n, - sizeof(n)); + &val, + sizeof(val)); } @else@ @printf "unrecognized type %s for %s" $i.type $i@ |