aboutsummaryrefslogtreecommitdiff
path: root/src/mysqlstat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mysqlstat.c')
-rw-r--r--src/mysqlstat.c509
1 files changed, 289 insertions, 220 deletions
diff --git a/src/mysqlstat.c b/src/mysqlstat.c
index 3e89424..938439a 100644
--- a/src/mysqlstat.c
+++ b/src/mysqlstat.c
@@ -1,4 +1,4 @@
-/* This file is part of Mysqlstat -*- autoconf -*-
+/* This file is part of Mysqlstat
* Copyright (C) 2014-2016 Sergey Poznyakoff
*
* Mysqlstat is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include <mysql/mysql.h>
#undef NDEBUG
#include <assert.h>
+#include "mysqlstat_mib.h"
static char *config_file = CONFDIR "/mysqlstat.cnf";
@@ -27,7 +28,7 @@ struct mysqlstat_connection {
};
static void *
-xalloc(size_t s)
+xmalloc(size_t s)
{
void *p = malloc(s);
assert(p != NULL);
@@ -65,7 +66,7 @@ mysqlstat_connect(void)
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",
+ snmp_log(LOG_ERR, "can't connect to MySQL: %s\n",
mysql_error(&conn->mysql));
free(conn);
conn = NULL;
@@ -82,280 +83,348 @@ mysqlstat_disconnect(mysqlstat_connection_t conn)
free(conn);
}
-struct syment {
- char *name;
- char *value;
-};
-
-static unsigned int hash_size[] = {
- 7, 17, 37, 101, 229, 487, 1009, 2039, 4091, 8191, 16411
-};
+unsigned mysqlstat_cache_timeout = CACHE_TIMEOUT;
-/* |max_rehash| keeps the number of entries in |hash_size| table. */
-static unsigned int max_rehash = sizeof(hash_size) / sizeof(hash_size[0]);
+#define __cat2__(a,b) a ## b
+#define ASSIGN_STRING(e,m,s) \
+ do { \
+ if (s) { \
+ (e)->__cat2__(m,_len) = strlen(s); \
+ (e)->m = xmalloc((e)->__cat2__(m,_len)); \
+ memcpy((e)->m, s, (e)->__cat2__(m,_len)); \
+ } else { \
+ (e)->__cat2__(m,_len) = 0; \
+ (e)->m = NULL; \
+ } \
+ } while (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;
-}
+#define ASSIGN_ROW(e,m,r) ASSIGN_STRING(e,m,(r)[__cat2__(FI_,m)])
-static int
-syment_matches(struct syment *ent, char const *name)
-{
- if (!ent->name)
- return 0;
- return strcmp(ent->name, name) == 0;
-}
+#define STREQ(pat,str) (strcmp(#pat, str) == 0)
-static uint32_t
-hash_string(const char *name, uint32_t hashsize)
+
+static long
+val_Slave_IO_Running(char const *val)
{
- unsigned i;
-
- for (i = 0; *name; name++) {
- i <<= 1;
- i ^= *(unsigned char*) name;
- }
- return i % hashsize;
+ if (strcmp(val, "Yes") == 0)
+ return 1;
+ else if (strcmp(val, "No") == 0)
+ return 2;
+ else if (strcmp(val, "Connected") == 0)
+ return 3;
+ return 4;
}
-static uint32_t
-find_insert_pos(struct hashtab *ht, struct syment *ent)
+static long
+val_bool(char const *val)
{
- 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;
+ if (strcmp(val, "Yes") == 0)
+ return 1;
+ return 2;
}
static void
-rehash(struct hashtab *ht)
+store_slave_status_row(struct replSlaveStatusTable_entry *ent,
+ char const *name, char const *value)
{
- struct syment *oldtab = ht->tab;
- uint32_t i, n;
-
- assert(ht->hc + 1 < max_rehash);
- n = hash_size[ht->hc];
- ++ht->hc;
- ht->tab = xcalloc(hash_size[ht->hc], sizeof(ht->tab[0]));
- for (i = 0; i < n; i++) {
- if (oldtab[i].name)
- ht->tab[find_insert_pos(ht, &oldtab[i])] = oldtab[i];
+ if (STREQ(Slave_IO_State, name)) {
+ ASSIGN_STRING(ent, replSlaveIOState, value);
+ } else if (STREQ(Master_Host, name)) {
+ ASSIGN_STRING(ent, replMasterHost, value);
+ } else if (STREQ(Master_User, name)) {
+ ASSIGN_STRING(ent, replMasterUser, value);
+ } else if (STREQ(Master_Port, name)) {
+ ent->replMasterPort = strtoul(value, NULL, 10);
+ } else if (STREQ(Connect_Retry, name)) {
+ ent->replConnectRetry = strtoul(value, NULL, 10);
+ } else if (STREQ(Master_Log_File, name)) {
+ ASSIGN_STRING(ent, replMasterLogFile, value);
+ } else if (STREQ(Read_Master_Log_Pos, name)) {
+ ent->replReadMasterLogPos = strtoul(value, NULL, 10);
+ } else if (STREQ(Relay_Log_File, name)) {
+ ASSIGN_STRING(ent, replRelayLogFile, value);
+ } else if (STREQ(Relay_Log_Pos, name)) {
+ ent->replRelayLogPos = strtoul(value, NULL, 10);
+ } else if (STREQ(Relay_Master_Log_File, name)) {
+ ASSIGN_STRING(ent, replMasterLogFile, value);
+ } else if (STREQ(Slave_IO_Running, name)) {
+ ent->replSlaveIORunning = val_Slave_IO_Running(value);
+ } else if (STREQ(Slave_SQL_Running, name)) {
+ ent->replSlaveSQLRunning = val_bool(value);
+ } else if (STREQ(Replicate_Do_DB, name)) {
+ ASSIGN_STRING(ent, replReplicateDoDB, value);
+ } else if (STREQ(Replicate_Ignore_DB, name)) {
+ ASSIGN_STRING(ent, replReplicateIgnoreDB, value);
+ } else if (STREQ(Replicate_Do_Table, name)) {
+ ASSIGN_STRING(ent, replReplicateDoTable, value);
+ } else if (STREQ(Replicate_Ignore_Table, name)) {
+ ASSIGN_STRING(ent, replReplicateIgnoreTable, value);
+ } else if (STREQ(Replicate_Wild_Do_Table, name)) {
+ ASSIGN_STRING(ent, replReplicateWildDoTable, value);
+ } else if (STREQ(Replicate_Wild_Ignore_Table, name)) {
+ ASSIGN_STRING(ent, replReplicateWildIgnoreTable, value);
+ } else if (STREQ(Last_IO_Errno, name)) {
+ ent->replLastIOErrno = strtoul(value, NULL, 10);
+ } else if (STREQ(Last_IO_Error, name)) {
+ ASSIGN_STRING(ent, replLastIOError, value);
+ } else if (STREQ(Last_SQL_Errno, name)) {
+ ent->replLastSQLErrno = strtoul(value, NULL, 10);
+ } else if (STREQ(Last_SQL_Error, name)) {
+ ASSIGN_STRING(ent, replLastSQLError, value);
+ } else if (STREQ(Skip_Counter, name)) {
+ ent->replSkipCounter = strtoul(value, NULL, 10);
+ } else if (STREQ(Exec_Master_Log_Pos, name)) {
+ ent->replExecMasterLogPos = strtoul(value, NULL, 10);
+ } else if (STREQ(Relay_Log_Space, name)) {
+ uint64_t n = strtoull(value, NULL, 10);
+ ent->replRelayLogSpace.high = n >> 32;
+ ent->replRelayLogSpace.low = n & 0xffffffff;
+ } else if (STREQ(Until_Condition, name)) {
+ ASSIGN_STRING(ent, replUntilCondition, value);
+ } else if (STREQ(Until_Log_File, name)) {
+ ASSIGN_STRING(ent, replUntilLogFile, value);
+ } else if (STREQ(Until_Log_Pos, name)) {
+ ASSIGN_STRING(ent, replUntilLogPos, value);
+ } else if (STREQ(Master_SSL_Allowed, name)) {
+ ASSIGN_STRING(ent, replMasterSSLAllowed, value);
+ } else if (STREQ(Master_SSL_CA_File, name)) {
+ ASSIGN_STRING(ent, replMasterSSLCAFile, value);
+ } else if (STREQ(Master_SSL_CA_Path, name)) {
+ ASSIGN_STRING(ent, replMasterSSLCAPath, value);
+ } else if (STREQ(Master_SSL_Cert, name)) {
+ ASSIGN_STRING(ent, replMasterSSLCert, value);
+ } else if (STREQ(Master_SSL_Cipher, name)) {
+ ASSIGN_STRING(ent, replMasterSSLCipher, value);
+ } else if (STREQ(Master_SSL_Key, name)) {
+ ASSIGN_STRING(ent, replMasterSSLKey, value);
+ } else if (STREQ(Seconds_Behind_Master, name)) {
+ ent->replSecondsBehindMaster = strtoul(value, NULL, 10) * 100;
+ } else if (STREQ(Master_SSL_Verify_Server_Cert, name)) {
+ ent->replMasterSSLVerifyServerCert = val_bool(value);
}
- free(oldtab);
}
-static void
-hashtab_remove(struct hashtab *ht, char const *name)
+int
+replSlaveStatusTable_load(netsnmp_cache *cache, void *vmagic)
{
- uint32_t pos, i, j, r;
+ mysqlstat_connection_t conn;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ MYSQL_FIELD *fields;
+ unsigned int num_fields, i;
+ netsnmp_tdata *table = (netsnmp_tdata *) vmagic;
+ struct replSlaveStatusTable_entry *ent;
+ netsnmp_tdata_row *data_row;
- 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
- }
+ conn = mysqlstat_connect();
+ if (!conn)
+ return SNMP_ERR_NOSUCHNAME;
- syment_free(&ht->tab[i]);
-
- for (;;) {
- ht->tab[i].name = ht->tab[i].value = NULL;
- j = i;
-
- do {
- i = (i + 1) % hash_size[ht->hc];
- if (!ht->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));
- ht->tab[j] = ht->tab[i];
+ DEBUGMSGTL(("mysqlstat", "Getting slave status\n"));
+ 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;
}
-}
-static char const *
-hashtab_lookup(struct hashtab *ht, char const *name)
-{
- uint32_t pos, i;
-
- 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].value;
- i = (i + 1) % hash_size[ht->hc];
- if (i == pos)
- break;
+ res = mysql_store_result(&conn->mysql);
+ if (mysql_num_rows(res) < 1) {
+ snmp_log(LOG_INFO, "empty slave status\n");
+ return 0;
}
- return NULL;
-}
-static void
-hashtab_install(struct hashtab *ht, char const *name, char const *value)
-{
- uint32_t i, pos;
- struct syment *ent;
-
- if (!value)
- value = "";
- DEBUGMSGTL(("mysqlstat", "%s = %s\n", name, value));
- 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 = xstrdup(value);
- return;
- }
- i = (i + 1) % hash_size[ht->hc];
- if (i == pos) {
- rehash(ht);
- i = pos = hash_string(name, hash_size[ht->hc]);
- }
+ num_fields = mysql_num_fields(res);
+ fields = mysql_fetch_fields(res);
+ row = mysql_fetch_row(res);
+
+ ent = SNMP_MALLOC_TYPEDEF(struct replSlaveStatusTable_entry);
+ if (!ent) {
+ mysqlstat_disconnect(conn);
+ return SNMP_ERR_GENERR;
}
- ht->tab[i].name = xstrdup(name);
- ht->tab[i].value = xstrdup(value);
-}
+ data_row = netsnmp_tdata_create_row();
+ if (!data_row) {
+ SNMP_FREE(ent);
+ mysqlstat_disconnect(conn);
+ return SNMP_ERR_GENERR;
+ }
+ data_row->data = ent;
+ ent->replSlaveIndex = 0;
+ netsnmp_tdata_row_add_index(data_row, ASN_INTEGER,
+ &ent->replSlaveIndex,
+ sizeof(ent->replSlaveIndex));
-void
-hashtab_clear(struct hashtab *ht)
-{
- unsigned i, hs;
+ netsnmp_tdata_add_row(table, data_row);
+
+ for (i = 0; i < num_fields; i++)
+ store_slave_status_row (ent, fields[i].name, row[i]);
- hs = hash_size[ht->hc];
- for (i = 0; i < hs; i++) {
- syment_free(&ht->tab[i]);
- }
+ mysql_free_result(res);
+ mysqlstat_disconnect(conn);
+ return 0;
}
-static struct hashtab *
-hashtab_create(void)
+void
+replSlaveStatusTable_entry_free(void *data)
{
- struct hashtab *ht = xalloc(sizeof(*ht));
- ht->hc = 0;
- ht->tab = xcalloc(hash_size[ht->hc], sizeof(ht->tab[0]));
- return ht;
+ struct replSlaveStatusTable_entry *ent = data;
+ free(ent->replSlaveIOState);
+ free(ent->replMasterLogFile);
+ free(ent->replRelayLogFile);
+ free(ent->replRelayMasterLogFile);
+ free(ent->replLastSQLError);
+ free(ent->replLastIOError);
+ free(ent->replMasterHost);
+ free(ent->replMasterUser);
+ free(ent->replReplicateDoDB);
+ free(ent->replReplicateIgnoreDB);
+ free(ent->replReplicateDoTable);
+ free(ent->replReplicateIgnoreTable);
+ free(ent->replReplicateWildDoTable);
+ free(ent->replReplicateWildIgnoreTable);
+ free(ent->replUntilCondition);
+ free(ent->replUntilLogFile);
+ free(ent->replUntilLogPos);
+ free(ent->replMasterSSLAllowed);
+ free(ent->replMasterSSLCAFile);
+ free(ent->replMasterSSLCAPath);
+ free(ent->replMasterSSLCert);
+ free(ent->replMasterSSLCipher);
+ free(ent->replMasterSSLKey);
}
-struct mysqlstat_cache {
- void (*populate) (struct hashtab *);
- struct hashtab *ht;
- time_t ts;
-};
-static unsigned cache_timeout = CACHE_TIMEOUT;
+enum {
+ FI_processID,
+ FI_processUser,
+ FI_processHost,
+ FI_processDatabase,
+ FI_processCommand,
+ FI_processTime,
+ FI_processState,
+ FI_processInfo
+};
-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 char const *
-val_Slave_IO_Running(char const *val)
+static void
+process_list_add(netsnmp_tdata *table_data, long idx, MYSQL_ROW mysql_row)
{
- if (strcmp(val, "Yes") == 0)
- return "1";
- else if (strcmp(val, "No") == 0)
- return "2";
- else if (strcmp(val, "Connected") == 0)
- return "3";
- return 4;
-}
+ struct processListTable_entry *ent;
+ netsnmp_tdata_row *data_row;
-static char const *
-val_bool(char const *val)
-{
- if (strcmp(val, "Yes") == 0)
- return "1";
- return "2";
+ ent = SNMP_MALLOC_TYPEDEF(struct processListTable_entry);
+ if (!ent)
+ return;
+
+ data_row = netsnmp_tdata_create_row();
+ if (!data_row) {
+ SNMP_FREE(ent);
+ return;
+ }
+ data_row->data = ent;
+
+ 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);
+ ASSIGN_ROW(ent, processDatabase, mysql_row);
+ ASSIGN_ROW(ent, processCommand, mysql_row);
+ if (mysql_row[FI_processTime])
+ ent->processTime = strtol(mysql_row[FI_processTime], NULL, 10) * 100;
+ ASSIGN_ROW(ent, processState, mysql_row);
+ ASSIGN_ROW(ent, processInfo, mysql_row);
+
+ netsnmp_tdata_row_add_index(data_row, ASN_INTEGER,
+ &ent->processIndex,
+ sizeof(ent->processIndex));
+
+ netsnmp_tdata_add_row(table_data, data_row);
}
-static void
-populate_repl(struct hashtab *ht)
+int
+processListTable_load(netsnmp_cache *cache, void *vmagic)
{
mysqlstat_connection_t conn;
MYSQL_RES *res;
- MYSQL_ROW row;
- MYSQL_FIELD *fields;
- unsigned int num_fields, i;
+ unsigned int num_rows, i;
+ netsnmp_tdata *table = (netsnmp_tdata *) vmagic;
+
+ DEBUGMSGTL(("mysqlstat", "Getting process list\n"));
conn = mysqlstat_connect();
if (!conn)
- return;
+ return SNMP_ERR_GENERR;
- DEBUGMSGTL(("mysqlstat", "Getting slave status\n"));
- if (mysql_query(&conn->mysql, "SHOW SLAVE STATUS")) {
- snmp_log(LOG_ERR, "can't get slave status: %s",
+ if (mysql_query(&conn->mysql, "SHOW PROCESSLIST")) {
+ snmp_log(LOG_ERR, "can't get slave process list: %s\n",
mysql_error(&conn->mysql));
- return;
+ 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");
- return;
- }
+ num_rows = mysql_num_rows(res);
- num_fields = mysql_num_fields(res);
- fields = mysql_fetch_fields(res);
- row = mysql_fetch_row(res);
- for (i = 0; i < num_fields; i++) {
- if (row[i]) {
- char const *val = row[i];
- /* FIXME: Move this conversion logic to mysqlstat_mib.mib2c */
- if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
- val = val_Slave_IO_Running(val);
- } else if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) {
- val = val_bool(val);
- } else if (strcmp(fields[i].name, "Master_SSL_Verify_Server_Cert") == 0) {
- val = val_bool(val);
- }
- hashtab_install(ht, fields[i].name, val);
- }
+ for (i = 0; i < num_rows; i++) {
+ MYSQL_ROW row;
+
+ mysql_data_seek(res, i);
+ row = mysql_fetch_row(res);
+
+ process_list_add(table, i, row);
}
+
mysql_free_result(res);
mysqlstat_disconnect(conn);
+
+ return 0;
}
-
-static struct mysqlstat_cache cache[MYSQLSTAT_MAX_CACHE] = {
- [MYSQLSTAT_CACHE_REPL] = { populate_repl }
-};
-char const *
-mysqlstat_get(int id, char const *name)
+void
+processListTable_entry_free(void *data)
{
- assert(id < sizeof(cache) / sizeof(cache[0]));
- return mysqlstat_cache_get(cache + id, name);
+ struct processListTable_entry *ent = data;
+ free(ent->processHost);
+ free(ent->processUser);
+ free(ent->processCommand);
+ free(ent->processState);
+ free(ent->processInfo);
}
+#if 0
+unsigned replSlaveTable_timeout = CACHE_TIMEOUT;
+
+static void
+replSlaveTable_entry_free(struct replSlaveTable_entry *ent)
+{
+}
+
+int
+replSlaveTable_load(netsnmp_cache *cache, void *vmagic)
+{
+}
+
+void
+replSlaveTable_free(netsnmp_cache *cache, void *vmagic)
+{
+ netsnmp_tdata *table = (netsnmp_tdata *) vmagic;
+ netsnmp_tdata_row *row;
+
+ DEBUGMSGTL(("mysqlstat", "freeing table\n"));
+ while ((row = netsnmp_tdata_row_first(table))) {
+ struct replSlaveTable_entry *entry = row->data;
+ free(ent->replSlaveHost);
+ free(ent->replSlaveUser);
+ free(ent->replSlaveCommand);
+ free(ent->replSlaveState);
+ free(ent->replSlaveInfo);
+ SNMP_FREE(ent);
+ netsnmp_tdata_remove_and_delete_row(table, row);
+ }
+}
+#endif

Return to:

Send suggestions and report system problems to the System administrator.