diff --git a/src/ckdb.c b/src/ckdb.c index 22a9d01b..5fc66caf 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -1778,10 +1778,10 @@ static void summarise_userstats() K_ITEM *first, *last, *new, *next, *tmp; USERSTATS *userstats, *us_first, *us_last, *us_next; double statrange, factor; - bool locked, upgrade; + bool locked, upgrade, issix, sixdiff; tv_t now, process, when; PGconn *conn = NULL; - int count; + int count, sixcount; char error[1024]; char tvbuf1[DATE_BUFSIZ], tvbuf2[DATE_BUFSIZ]; @@ -1838,6 +1838,8 @@ static void summarise_userstats() next = next_in_ktree(ctx); upgrade = true; + issix = us_first->six; + sixdiff = false; K_ULOCK(userstats_free); new = k_unlink_head(userstats_free); DATA_USERSTATS(userstats, new); @@ -1850,6 +1852,7 @@ static void summarise_userstats() k_add_head(userstats_summ, first); count = 1; + sixcount = issix ? 1 : 0; while (next) { DATA_USERSTATS(us_next, next); statrange = tvdiff(&when, &(us_next->statsdate)); @@ -1861,7 +1864,10 @@ static void summarise_userstats() if (us_next->summarylevel[0] == SUMMARY_NONE && us_next->userid == userstats->userid && strcmp(us_next->workername, userstats->workername) == 0) { + if (us_next->six != issix) + sixdiff = true; count++; + sixcount += us_next->six ? 1 : 0; userstats->hashrate += us_next->hashrate; userstats->hashrate5m += us_next->hashrate5m; userstats->hashrate1hr += us_next->hashrate1hr; @@ -1870,8 +1876,10 @@ static void summarise_userstats() userstats->elapsed = us_next->elapsed; userstats->summarycount += us_next->summarycount; - userstats_root = remove_from_ktree(userstats_root, next, cmp_userstats); - userstats_statsdate_root = remove_from_ktree(userstats_statsdate_root, next, + userstats_root = remove_from_ktree(userstats_root, + next, cmp_userstats); + userstats_statsdate_root = remove_from_ktree(userstats_statsdate_root, + next, cmp_userstats_statsdate); k_unlink_item(userstats_store, next); k_add_head(userstats_summ, next); @@ -1895,8 +1903,14 @@ static void summarise_userstats() userstats->summarylevel[0] = SUMMARY_DB; userstats->summarylevel[1] = '\0'; - // Expect 6 per poolinstance - factor = (double)count / 6.0; + if (issix && !sixdiff) { + // Expect 6 per poolinstance + factor = (double)count / 6.0; + } else { + // For now ... new format is still 6 per hour + factor = (double)count / 6.0; + } + userstats->hashrate *= factor; userstats->hashrate5m *= factor; userstats->hashrate1hr *= factor; @@ -2434,6 +2448,7 @@ static void *socketer(__maybe_unused void *arg) case CMD_SHARELOG: case CMD_POOLSTAT: case CMD_USERSTAT: + case CMD_WORKERSTAT: case CMD_BLOCK: // First message from the pool if (want_first) { @@ -2601,6 +2616,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) case CMD_HEARTBEAT: case CMD_POOLSTAT: case CMD_USERSTAT: + case CMD_WORKERSTAT: case CMD_BLOCK: if (confirm_sharesummary) break; diff --git a/src/ckdb.h b/src/ckdb.h index 1beaf0eb..be0be7e8 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "0.9.6" -#define CKDB_VERSION DB_VERSION"-0.744" +#define CKDB_VERSION DB_VERSION"-0.750" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -296,6 +296,7 @@ enum cmd_values { CMD_WORKERSET, CMD_POOLSTAT, CMD_USERSTAT, + CMD_WORKERSTAT, CMD_BLOCK, CMD_BLOCKLIST, CMD_BLOCKSTATUS, @@ -1173,6 +1174,7 @@ typedef struct userstats { double hashrate1hr; double hashrate24hr; bool idle; // Non-db field + bool six; // Non-db field char summarylevel[TXT_FLAG+1]; // Initially SUMMARY_NONE in RAM int32_t summarycount; tv_t statsdate; @@ -1772,6 +1774,11 @@ extern bool userstats_add(char *poolinstance, char *elapsed, char *username, char *hashrate1hr, char *hashrate24hr, bool idle, bool eos, char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root); +extern bool workerstats_add(char *poolinstance, char *elapsed, char *username, + char *workername, char *hashrate, char *hashrate5m, + char *hashrate1hr, char *hashrate24hr, bool idle, + char *by, char *code, char *inet, tv_t *cd, + K_TREE *trf_root); extern bool userstats_fill(PGconn *conn); extern bool markersummary_fill(PGconn *conn); #define workmarkers_process(_conn, _add, _markerid, _poolinstance, \ diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 369d7a73..ae524de8 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -728,6 +728,79 @@ static char *cmd_userstats(__maybe_unused PGconn *conn, char *cmd, char *id, return strdup(reply); } +static char *cmd_workerstats(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *notnow, char *by, char *code, + char *inet, tv_t *cd, K_TREE *trf_root) +{ + char reply[1024] = ""; + size_t siz = sizeof(reply); + + // log to logfile + + K_ITEM *i_poolinstance, *i_elapsed, *i_username, *i_workername; + K_ITEM *i_hashrate, *i_hashrate5m, *i_hashrate1hr, *i_hashrate24hr; + K_ITEM *i_idle; + bool ok = false, idle; + + LOGDEBUG("%s(): cmd '%s'", __func__, cmd); + + i_poolinstance = require_name(trf_root, "poolinstance", 1, NULL, reply, siz); + if (!i_poolinstance) + return strdup(reply); + + i_elapsed = require_name(trf_root, "elapsed", 1, NULL, reply, siz); + if (!i_elapsed) + return strdup(reply); + + i_username = require_name(trf_root, "username", 1, NULL, reply, siz); + if (!i_username) + return strdup(reply); + + i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz); + if (!i_workername) + return strdup(reply); + + i_hashrate = require_name(trf_root, "hashrate", 1, NULL, reply, siz); + if (!i_hashrate) + return strdup(reply); + + i_hashrate5m = require_name(trf_root, "hashrate5m", 1, NULL, reply, siz); + if (!i_hashrate5m) + return strdup(reply); + + i_hashrate1hr = require_name(trf_root, "hashrate1hr", 1, NULL, reply, siz); + if (!i_hashrate1hr) + return strdup(reply); + + i_hashrate24hr = require_name(trf_root, "hashrate24hr", 1, NULL, reply, siz); + if (!i_hashrate24hr) + return strdup(reply); + + i_idle = require_name(trf_root, "idle", 1, NULL, reply, siz); + if (!i_idle) + return strdup(reply); + + idle = (strcasecmp(transfer_data(i_idle), TRUE_STR) == 0); + + ok = workerstats_add(transfer_data(i_poolinstance), + transfer_data(i_elapsed), + transfer_data(i_username), + transfer_data(i_workername), + transfer_data(i_hashrate), + transfer_data(i_hashrate5m), + transfer_data(i_hashrate1hr), + transfer_data(i_hashrate24hr), + idle, by, code, inet, cd, trf_root); + + if (!ok) { + LOGERR("%s() %s.failed.DATA", __func__, id); + return strdup("failed.DATA"); + } + LOGDEBUG("%s.ok.", id); + snprintf(reply, siz, "ok."); + return strdup(reply); +} + static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, __maybe_unused char *inet, @@ -4126,6 +4199,7 @@ struct CMDS ckdb_cmds[] = { { CMD_WORKERSET,"workerset", false, false, cmd_workerset, ACCESS_WEB }, { CMD_POOLSTAT, "poolstats", false, true, cmd_poolstats, ACCESS_POOL }, { CMD_USERSTAT, "userstats", false, true, cmd_userstats, ACCESS_POOL }, + { CMD_WORKERSTAT,"workerstats", false, true, cmd_workerstats,ACCESS_POOL }, { CMD_BLOCK, "block", false, true, cmd_blocks, ACCESS_POOL }, { CMD_BLOCKLIST,"blocklist", false, false, cmd_blocklist, ACCESS_WEB }, { CMD_BLOCKSTATUS,"blockstatus",false, false, cmd_blockstatus,ACCESS_WEB }, diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index 42be0f87..ff199fc5 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -4686,6 +4686,7 @@ bool userstats_add(char *poolinstance, char *elapsed, char *username, SIMPLEDATEINIT(row, cd, by, code, inet); SIMPLEDATETRANSFER(trf_root, row); copy_tv(&(row->statsdate), &(row->createdate)); + row->six = true; if (eos) { // Save it for end processing @@ -4788,6 +4789,89 @@ advancetogo: return true; } +// This is to RAM. The summariser calls the DB I/O functions for userstats +bool workerstats_add(char *poolinstance, char *elapsed, char *username, + char *workername, char *hashrate, char *hashrate5m, + char *hashrate1hr, char *hashrate24hr, bool idle, + char *by, char *code, char *inet, tv_t *cd, + K_TREE *trf_root) +{ + K_ITEM *us_item, *u_item, *us_match, look; + USERSTATS *row, cmp, *match; + USERS *users; + K_TREE_CTX ctx[1]; + + LOGDEBUG("%s(): add", __func__); + + K_WLOCK(userstats_free); + us_item = k_unlink_head(userstats_free); + K_WUNLOCK(userstats_free); + + DATA_USERSTATS(row, us_item); + + STRNCPY(row->poolinstance, poolinstance); + TXT_TO_BIGINT("elapsed", elapsed, row->elapsed); + K_RLOCK(users_free); + u_item = find_users(username); + K_RUNLOCK(users_free); + if (!u_item) + return false; + DATA_USERS(users, u_item); + row->userid = users->userid; + TXT_TO_STR("workername", workername, row->workername); + TXT_TO_DOUBLE("hashrate", hashrate, row->hashrate); + TXT_TO_DOUBLE("hashrate5m", hashrate5m, row->hashrate5m); + TXT_TO_DOUBLE("hashrate1hr", hashrate1hr, row->hashrate1hr); + TXT_TO_DOUBLE("hashrate24hr", hashrate24hr, row->hashrate24hr); + row->idle = idle; + row->summarylevel[0] = SUMMARY_NONE; + row->summarylevel[1] = '\0'; + row->summarycount = 1; + SIMPLEDATEINIT(row, cd, by, code, inet); + SIMPLEDATETRANSFER(trf_root, row); + copy_tv(&(row->statsdate), &(row->createdate)); + row->six = false; + + // confirm_summaries() doesn't call this + if (reloading) { + memcpy(&cmp, row, sizeof(cmp)); + INIT_USERSTATS(&look); + look.data = (void *)(&cmp); + // Just zero it to ensure the DB record is after it, not equal to it + cmp.statsdate.tv_usec = 0; + /* If there is a matching user+worker DB record summarising this row, + * or a matching user+worker DB record next after this row, discard it */ + us_match = find_after_in_ktree(userstats_workerstatus_root, &look, + cmp_userstats_workerstatus, ctx); + DATA_USERSTATS_NULL(match, us_match); + if (us_match && + match->userid == row->userid && + strcmp(match->workername, row->workername) == 0 && + match->summarylevel[0] != SUMMARY_NONE) { + K_WLOCK(userstats_free); + k_add_head(userstats_free, us_item); + K_WUNLOCK(userstats_free); + return true; + } + } + + workerstatus_update(NULL, NULL, row); + + K_WLOCK(userstats_free); + userstats_root = add_to_ktree(userstats_root, us_item, cmp_userstats); + userstats_statsdate_root = add_to_ktree(userstats_statsdate_root, us_item, + cmp_userstats_statsdate); + if (!startup_complete) { + userstats_workerstatus_root = add_to_ktree(userstats_workerstatus_root, + us_item, + cmp_userstats_workerstatus); + } + k_add_head(userstats_store, us_item); + K_WUNLOCK(userstats_free); + + return true; +} + // TODO: data selection - only require ? bool userstats_fill(PGconn *conn) {