|
|
@ -94,7 +94,7 @@ static char *restorefrom; |
|
|
|
* non db records - will depend on TODO: pool stats reporting |
|
|
|
* non db records - will depend on TODO: pool stats reporting |
|
|
|
* requirements |
|
|
|
* requirements |
|
|
|
* DB+RAM userstats: for each pool/user/worker it would be the start |
|
|
|
* DB+RAM userstats: for each pool/user/worker it would be the start |
|
|
|
* of the next time band after the last DB createdate, |
|
|
|
* of the time band containing the DB statsdate, |
|
|
|
* since all previous data was summarised and deleted - |
|
|
|
* since all previous data was summarised and deleted - |
|
|
|
* use the oldest of these for all pools/users/workers |
|
|
|
* use the oldest of these for all pools/users/workers |
|
|
|
* TODO: multiple pools is not yet handled by ckdb |
|
|
|
* TODO: multiple pools is not yet handled by ckdb |
|
|
@ -1035,6 +1035,7 @@ typedef struct userstats { |
|
|
|
#define DATA_USERSTATS(_item) ((USERSTATS *)(_item->data)) |
|
|
|
#define DATA_USERSTATS(_item) ((USERSTATS *)(_item->data)) |
|
|
|
|
|
|
|
|
|
|
|
static K_TREE *userstats_root; |
|
|
|
static K_TREE *userstats_root; |
|
|
|
|
|
|
|
static K_TREE *userstats_statsdate_root; // ordered by statsdate first
|
|
|
|
static K_LIST *userstats_list; |
|
|
|
static K_LIST *userstats_list; |
|
|
|
static K_STORE *userstats_store; |
|
|
|
static K_STORE *userstats_store; |
|
|
|
// Awaiting EOS
|
|
|
|
// Awaiting EOS
|
|
|
@ -1683,7 +1684,7 @@ static double cmp_workerstatus(K_ITEM *a, K_ITEM *b) |
|
|
|
return c; |
|
|
|
return c; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static K_ITEM *find_workerstatus(int64_t userid, char *workername) |
|
|
|
static K_ITEM *get_workerstatus(int64_t userid, char *workername) |
|
|
|
{ |
|
|
|
{ |
|
|
|
WORKERSTATUS workerstatus; |
|
|
|
WORKERSTATUS workerstatus; |
|
|
|
K_TREE_CTX ctx[1]; |
|
|
|
K_TREE_CTX ctx[1]; |
|
|
@ -1701,7 +1702,7 @@ static K_ITEM *_find_create_workerstatus(int64_t userid, char *workername, bool |
|
|
|
K_ITEM *item = NULL; |
|
|
|
K_ITEM *item = NULL; |
|
|
|
WORKERSTATUS *row; |
|
|
|
WORKERSTATUS *row; |
|
|
|
|
|
|
|
|
|
|
|
item = find_workerstatus(userid, workername); |
|
|
|
item = get_workerstatus(userid, workername); |
|
|
|
if (!item && create) { |
|
|
|
if (!item && create) { |
|
|
|
K_WLOCK(workerstatus_list); |
|
|
|
K_WLOCK(workerstatus_list); |
|
|
|
item = k_unlink_head(workerstatus_list); |
|
|
|
item = k_unlink_head(workerstatus_list); |
|
|
@ -4531,6 +4532,27 @@ static double cmp_userstats_workername(K_ITEM *a, K_ITEM *b) |
|
|
|
return c; |
|
|
|
return c; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* order by statsdate,userid asc,statsdate asc,workername asc,poolinstance asc
|
|
|
|
|
|
|
|
as per required for DB summarisation */ |
|
|
|
|
|
|
|
static double cmp_userstats_statsdate(K_ITEM *a, K_ITEM *b) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
double c = tvdiff(&(DATA_USERSTATS(a)->statsdate), |
|
|
|
|
|
|
|
&(DATA_USERSTATS(b)->statsdate)); |
|
|
|
|
|
|
|
if (c == 0) { |
|
|
|
|
|
|
|
c = (double)(DATA_USERSTATS(a)->userid - |
|
|
|
|
|
|
|
DATA_USERSTATS(b)->userid); |
|
|
|
|
|
|
|
if (c == 0) { |
|
|
|
|
|
|
|
c = (double)strcmp(DATA_USERSTATS(a)->workername, |
|
|
|
|
|
|
|
DATA_USERSTATS(b)->workername); |
|
|
|
|
|
|
|
if (c == 0) { |
|
|
|
|
|
|
|
c = (double)strcmp(DATA_USERSTATS(a)->poolinstance, |
|
|
|
|
|
|
|
DATA_USERSTATS(b)->poolinstance); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return c; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool userstats_add_db(PGconn *conn, USERSTATS *row) |
|
|
|
static bool userstats_add_db(PGconn *conn, USERSTATS *row) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ExecStatusType rescode; |
|
|
|
ExecStatusType rescode; |
|
|
@ -4663,6 +4685,8 @@ static bool userstats_add(char *poolinstance, char *elapsed, char *username, |
|
|
|
k_unlink_item(userstats_eos_store, us_match); |
|
|
|
k_unlink_item(userstats_eos_store, us_match); |
|
|
|
userstats_root = add_to_ktree(userstats_root, us_match, |
|
|
|
userstats_root = add_to_ktree(userstats_root, us_match, |
|
|
|
cmp_userstats); |
|
|
|
cmp_userstats); |
|
|
|
|
|
|
|
userstats_statsdate_root = add_to_ktree(userstats_statsdate_root, us_match, |
|
|
|
|
|
|
|
cmp_userstats_statsdate); |
|
|
|
k_add_head(userstats_store, us_match); |
|
|
|
k_add_head(userstats_store, us_match); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -4685,13 +4709,15 @@ static void userstats_update_ccl(USERSTATS *row) |
|
|
|
userstats.userid = row->userid; |
|
|
|
userstats.userid = row->userid; |
|
|
|
STRNCPY(userstats.workername, row->workername); |
|
|
|
STRNCPY(userstats.workername, row->workername); |
|
|
|
memcpy(&(userstats.statsdate), &(row->statsdate), sizeof(row->statsdate)); |
|
|
|
memcpy(&(userstats.statsdate), &(row->statsdate), sizeof(row->statsdate)); |
|
|
|
// Start of the next timeband after this row
|
|
|
|
// Start of this timeband
|
|
|
|
switch (row->summarylevel[0]) { |
|
|
|
switch (row->summarylevel[0]) { |
|
|
|
case SUMMARY_DB: |
|
|
|
case SUMMARY_DB: |
|
|
|
userstats.statsdate.tv_sec += USERSTATS_DB_S; |
|
|
|
userstats.statsdate.tv_sec -= userstats.statsdate.tv_sec % USERSTATS_DB_S; |
|
|
|
|
|
|
|
userstats.statsdate.tv_usec = 0; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case SUMMARY_FULL: |
|
|
|
case SUMMARY_FULL: |
|
|
|
userstats.statsdate.tv_sec += USERSTATS_DB_DS; |
|
|
|
userstats.statsdate.tv_sec -= userstats.statsdate.tv_sec % USERSTATS_DB_DS; |
|
|
|
|
|
|
|
userstats.statsdate.tv_usec = 0; |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
tv_to_buf(&(row->statsdate), buf, sizeof(buf)); |
|
|
|
tv_to_buf(&(row->statsdate), buf, sizeof(buf)); |
|
|
@ -4822,6 +4848,8 @@ static bool userstats_fill(PGconn *conn) |
|
|
|
row->idle = false; |
|
|
|
row->idle = false; |
|
|
|
|
|
|
|
|
|
|
|
userstats_root = add_to_ktree(userstats_root, item, cmp_userstats); |
|
|
|
userstats_root = add_to_ktree(userstats_root, item, cmp_userstats); |
|
|
|
|
|
|
|
userstats_statsdate_root = add_to_ktree(userstats_statsdate_root, item, |
|
|
|
|
|
|
|
cmp_userstats_statsdate); |
|
|
|
k_add_head(userstats_store, item); |
|
|
|
k_add_head(userstats_store, item); |
|
|
|
|
|
|
|
|
|
|
|
workerstatus_update(NULL, NULL, row, NULL); |
|
|
|
workerstatus_update(NULL, NULL, row, NULL); |
|
|
@ -4847,6 +4875,7 @@ void userstats_reload() |
|
|
|
|
|
|
|
|
|
|
|
K_WLOCK(userstats_list); |
|
|
|
K_WLOCK(userstats_list); |
|
|
|
userstats_root = free_ktree(userstats_root, NULL); |
|
|
|
userstats_root = free_ktree(userstats_root, NULL); |
|
|
|
|
|
|
|
userstats_statsdate_root = free_ktree(userstats_statsdate_root, NULL); |
|
|
|
k_list_transfer_to_head(userstats_store, userstats_list); |
|
|
|
k_list_transfer_to_head(userstats_store, userstats_list); |
|
|
|
K_WUNLOCK(userstats_list); |
|
|
|
K_WUNLOCK(userstats_list); |
|
|
|
|
|
|
|
|
|
|
@ -5133,6 +5162,7 @@ static bool setup_data() |
|
|
|
userstats_summ = k_new_store(userstats_list); |
|
|
|
userstats_summ = k_new_store(userstats_list); |
|
|
|
userstats_ccl = k_new_store(userstats_list); |
|
|
|
userstats_ccl = k_new_store(userstats_list); |
|
|
|
userstats_root = new_ktree(); |
|
|
|
userstats_root = new_ktree(); |
|
|
|
|
|
|
|
userstats_statsdate_root = new_ktree(); |
|
|
|
userstats_list->dsp_func = dsp_userstats; |
|
|
|
userstats_list->dsp_func = dsp_userstats; |
|
|
|
userstats_ccl_root = new_ktree(); |
|
|
|
userstats_ccl_root = new_ktree(); |
|
|
|
|
|
|
|
|
|
|
@ -5155,6 +5185,7 @@ static bool setup_data() |
|
|
|
|
|
|
|
|
|
|
|
bzero(&statsdate, sizeof(statsdate)); |
|
|
|
bzero(&statsdate, sizeof(statsdate)); |
|
|
|
ccl = userstats_ccl->head; |
|
|
|
ccl = userstats_ccl->head; |
|
|
|
|
|
|
|
// oldest in ccl
|
|
|
|
while (ccl) { |
|
|
|
while (ccl) { |
|
|
|
if (statsdate.tv_sec == 0 || |
|
|
|
if (statsdate.tv_sec == 0 || |
|
|
|
!tv_newer(&statsdate, &(DATA_USERSTATS(ccl)->statsdate))) |
|
|
|
!tv_newer(&statsdate, &(DATA_USERSTATS(ccl)->statsdate))) |
|
|
@ -5709,7 +5740,7 @@ static char *cmd_allusers(char *cmd, char *id, __maybe_unused tv_t *now, __maybe |
|
|
|
// Find last records for each user/worker in ALLUSERS_LIMIT_S
|
|
|
|
// Find last records for each user/worker in ALLUSERS_LIMIT_S
|
|
|
|
// TODO: include pool_instance
|
|
|
|
// TODO: include pool_instance
|
|
|
|
K_WLOCK(userstats_list); |
|
|
|
K_WLOCK(userstats_list); |
|
|
|
us_item = last_in_ktree(userstats_root, us_ctx); |
|
|
|
us_item = last_in_ktree(userstats_statsdate_root, us_ctx); |
|
|
|
while (us_item && tvdiff(now, &(DATA_USERSTATS(us_item)->statsdate)) < ALLUSERS_LIMIT_S) { |
|
|
|
while (us_item && tvdiff(now, &(DATA_USERSTATS(us_item)->statsdate)) < ALLUSERS_LIMIT_S) { |
|
|
|
usw_item = find_in_ktree(userstats_workername_root, us_item, cmp_userstats_workername, usw_ctx); |
|
|
|
usw_item = find_in_ktree(userstats_workername_root, us_item, cmp_userstats_workername, usw_ctx); |
|
|
|
if (!usw_item) { |
|
|
|
if (!usw_item) { |
|
|
@ -5721,7 +5752,7 @@ static char *cmd_allusers(char *cmd, char *id, __maybe_unused tv_t *now, __maybe |
|
|
|
|
|
|
|
|
|
|
|
userstats_workername_root = add_to_ktree(userstats_workername_root, usw_item, cmp_userstats_workername); |
|
|
|
userstats_workername_root = add_to_ktree(userstats_workername_root, usw_item, cmp_userstats_workername); |
|
|
|
} |
|
|
|
} |
|
|
|
us_item = us_item->prev; |
|
|
|
us_item = prev_in_ktree(us_ctx); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
APPEND_REALLOC_INIT(buf, off, len); |
|
|
|
APPEND_REALLOC_INIT(buf, off, len); |
|
|
@ -6587,7 +6618,7 @@ static void summarise_poolstats() |
|
|
|
static void summarise_userstats() |
|
|
|
static void summarise_userstats() |
|
|
|
{ |
|
|
|
{ |
|
|
|
K_TREE_CTX ctx[1], ctx2[1]; |
|
|
|
K_TREE_CTX ctx[1], ctx2[1]; |
|
|
|
K_ITEM *tail, *new, *prev, *tmp; |
|
|
|
K_ITEM *first, *new, *next, *tmp; |
|
|
|
USERSTATS *userstats; |
|
|
|
USERSTATS *userstats; |
|
|
|
double statrange, factor; |
|
|
|
double statrange, factor; |
|
|
|
bool locked, upgrade; |
|
|
|
bool locked, upgrade; |
|
|
@ -6601,20 +6632,20 @@ static void summarise_userstats() |
|
|
|
upgrade = false; |
|
|
|
upgrade = false; |
|
|
|
locked = true; |
|
|
|
locked = true; |
|
|
|
K_ILOCK(userstats_list); |
|
|
|
K_ILOCK(userstats_list); |
|
|
|
tail = last_in_ktree(userstats_root, ctx); |
|
|
|
first = first_in_ktree(userstats_statsdate_root, ctx); |
|
|
|
// Last non DB stat
|
|
|
|
// Oldest non DB stat
|
|
|
|
while (tail && DATA_USERSTATS(tail)->poolinstance[0] == '\0') |
|
|
|
while (first && DATA_USERSTATS(first)->summarylevel[0] != SUMMARY_NONE) |
|
|
|
tail = prev_in_ktree(ctx); |
|
|
|
first = next_in_ktree(ctx); |
|
|
|
|
|
|
|
|
|
|
|
if (!tail) |
|
|
|
if (!first) |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
statrange = tvdiff(&now, &(DATA_USERSTATS(tail)->statsdate)); |
|
|
|
statrange = tvdiff(&now, &(DATA_USERSTATS(first)->statsdate)); |
|
|
|
// Is there data ready for summarising?
|
|
|
|
// Is there data ready for summarising?
|
|
|
|
if (statrange <= USERSTATS_AGE) |
|
|
|
if (statrange <= USERSTATS_AGE) |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
memcpy(&when, &(DATA_USERSTATS(tail)->statsdate), sizeof(when)); |
|
|
|
memcpy(&when, &(DATA_USERSTATS(first)->statsdate), sizeof(when)); |
|
|
|
/* Convert when to the start of the timeframe after the one it is in
|
|
|
|
/* Convert when to the start of the timeframe after the one it is in
|
|
|
|
* assume timeval ignores leapseconds ... */ |
|
|
|
* assume timeval ignores leapseconds ... */ |
|
|
|
when.tv_sec = when.tv_sec - (when.tv_sec % USERSTATS_DB_S) + USERSTATS_DB_S; |
|
|
|
when.tv_sec = when.tv_sec - (when.tv_sec % USERSTATS_DB_S) + USERSTATS_DB_S; |
|
|
@ -6625,41 +6656,43 @@ static void summarise_userstats() |
|
|
|
if (statrange < USERSTATS_AGE) |
|
|
|
if (statrange < USERSTATS_AGE) |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
prev = prev_in_ktree(ctx); |
|
|
|
next = next_in_ktree(ctx); |
|
|
|
|
|
|
|
|
|
|
|
upgrade = true; |
|
|
|
upgrade = true; |
|
|
|
K_ULOCK(userstats_list); |
|
|
|
K_ULOCK(userstats_list); |
|
|
|
new = k_unlink_head(userstats_list); |
|
|
|
new = k_unlink_head(userstats_list); |
|
|
|
userstats = DATA_USERSTATS(new); |
|
|
|
userstats = DATA_USERSTATS(new); |
|
|
|
memcpy(userstats, DATA_USERSTATS(tail), sizeof(USERSTATS)); |
|
|
|
memcpy(userstats, DATA_USERSTATS(first), sizeof(USERSTATS)); |
|
|
|
|
|
|
|
|
|
|
|
remove_from_ktree(userstats_root, tail, cmp_userstats, ctx2); |
|
|
|
remove_from_ktree(userstats_root, first, cmp_userstats, ctx2); |
|
|
|
k_unlink_item(userstats_store, tail); |
|
|
|
remove_from_ktree(userstats_statsdate_root, first, cmp_userstats_statsdate, ctx2); |
|
|
|
k_add_head(userstats_summ, tail); |
|
|
|
k_unlink_item(userstats_store, first); |
|
|
|
|
|
|
|
k_add_head(userstats_summ, first); |
|
|
|
|
|
|
|
|
|
|
|
count = 1; |
|
|
|
count = 1; |
|
|
|
while (prev) { |
|
|
|
while (next) { |
|
|
|
if (DATA_USERSTATS(prev)->userid != userstats->userid) |
|
|
|
if (DATA_USERSTATS(next)->userid != userstats->userid) |
|
|
|
break; |
|
|
|
break; |
|
|
|
if (strcmp(DATA_USERSTATS(prev)->workername, userstats->workername)) |
|
|
|
if (strcmp(DATA_USERSTATS(next)->workername, userstats->workername)) |
|
|
|
break; |
|
|
|
break; |
|
|
|
statrange = tvdiff(&when, &(DATA_USERSTATS(prev)->statsdate)); |
|
|
|
statrange = tvdiff(&when, &(DATA_USERSTATS(next)->statsdate)); |
|
|
|
if (statrange <= 0) |
|
|
|
if (statrange <= 0) |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
count++; |
|
|
|
count++; |
|
|
|
userstats->hashrate += DATA_USERSTATS(prev)->hashrate; |
|
|
|
userstats->hashrate += DATA_USERSTATS(next)->hashrate; |
|
|
|
userstats->hashrate5m += DATA_USERSTATS(prev)->hashrate5m; |
|
|
|
userstats->hashrate5m += DATA_USERSTATS(next)->hashrate5m; |
|
|
|
userstats->hashrate1hr += DATA_USERSTATS(prev)->hashrate1hr; |
|
|
|
userstats->hashrate1hr += DATA_USERSTATS(next)->hashrate1hr; |
|
|
|
userstats->hashrate24hr += DATA_USERSTATS(prev)->hashrate24hr; |
|
|
|
userstats->hashrate24hr += DATA_USERSTATS(next)->hashrate24hr; |
|
|
|
if (userstats->elapsed > DATA_USERSTATS(prev)->elapsed) |
|
|
|
if (userstats->elapsed > DATA_USERSTATS(next)->elapsed) |
|
|
|
userstats->elapsed = DATA_USERSTATS(prev)->elapsed; |
|
|
|
userstats->elapsed = DATA_USERSTATS(next)->elapsed; |
|
|
|
|
|
|
|
|
|
|
|
tmp = prev_in_ktree(ctx); |
|
|
|
tmp = next_in_ktree(ctx); |
|
|
|
remove_from_ktree(userstats_root, prev, cmp_userstats, ctx2); |
|
|
|
remove_from_ktree(userstats_root, next, cmp_userstats, ctx2); |
|
|
|
k_unlink_item(userstats_store, prev); |
|
|
|
remove_from_ktree(userstats_statsdate_root, next, cmp_userstats_statsdate, ctx2); |
|
|
|
k_add_head(userstats_summ, prev); |
|
|
|
k_unlink_item(userstats_store, next); |
|
|
|
prev = tmp; |
|
|
|
k_add_head(userstats_summ, next); |
|
|
|
|
|
|
|
next = tmp; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (userstats->hashrate5m > 0.0 || userstats->hashrate1hr > 0.0) |
|
|
|
if (userstats->hashrate5m > 0.0 || userstats->hashrate1hr > 0.0) |
|
|
@ -6693,6 +6726,7 @@ static void summarise_userstats() |
|
|
|
tmp = userstats_summ->head; |
|
|
|
tmp = userstats_summ->head; |
|
|
|
while (tmp) { |
|
|
|
while (tmp) { |
|
|
|
add_to_ktree(userstats_root, tmp, cmp_userstats); |
|
|
|
add_to_ktree(userstats_root, tmp, cmp_userstats); |
|
|
|
|
|
|
|
add_to_ktree(userstats_statsdate_root, tmp, cmp_userstats_statsdate); |
|
|
|
tmp = tmp->next; |
|
|
|
tmp = tmp->next; |
|
|
|
} |
|
|
|
} |
|
|
|
k_list_transfer_to_tail(userstats_summ, userstats_store); |
|
|
|
k_list_transfer_to_tail(userstats_summ, userstats_store); |
|
|
@ -6701,6 +6735,7 @@ static void summarise_userstats() |
|
|
|
|
|
|
|
|
|
|
|
k_list_transfer_to_tail(userstats_summ, userstats_list); |
|
|
|
k_list_transfer_to_tail(userstats_summ, userstats_list); |
|
|
|
add_to_ktree(userstats_root, new, cmp_userstats); |
|
|
|
add_to_ktree(userstats_root, new, cmp_userstats); |
|
|
|
|
|
|
|
add_to_ktree(userstats_statsdate_root, new, cmp_userstats_statsdate); |
|
|
|
|
|
|
|
|
|
|
|
if (upgrade) |
|
|
|
if (upgrade) |
|
|
|
K_WUNLOCK(userstats_list); |
|
|
|
K_WUNLOCK(userstats_list); |
|
|
|