Browse Source

ckdb/php - store, and use, the block and prevous valid block createtime in BLOCKS

master
kanoi 9 years ago
parent
commit
4c243f24cc
  1. 2
      pool/page_blocks.php
  2. 11
      src/ckdb.c
  3. 23
      src/ckdb.h
  4. 78
      src/ckdb_cmd.c
  5. 282
      src/ckdb_data.c
  6. 106
      src/ckdb_dbio.c

2
pool/page_blocks.php

@ -111,7 +111,7 @@ function doblocks($data, $user)
$row = 'odd';
$desc = $ans['s_desc:'.$i];
$age = gmdate('j/M H:i',$ans['s_createdate:'.$i]);
$age = daysago($since - $ans['s_prevcreatedate:'.$i]);
$diff = number_format(100 * $ans['s_diffratio:'.$i], 2);
$mean = number_format(100 * $ans['s_diffmean:'.$i], 2);

11
src/ckdb.c

@ -1483,8 +1483,7 @@ static bool setup_data()
if (workinfo_current) {
DATA_WORKINFO(wic, workinfo_current);
STRNCPY(wi.coinbase1, wic->coinbase1);
wi.createdate.tv_sec = 0L;
wi.createdate.tv_usec = 0L;
DATE_ZERO(&(wi.createdate));
INIT_WORKINFO(&look);
look.data = (void *)(&wi);
// Find the first workinfo for this height
@ -1524,7 +1523,7 @@ static bool setup_data()
(_seqset)->seqdata[_i].firsttime.tv_sec = \
(_seqset)->seqdata[_i].firsttime.tv_usec = \
(_seqset)->seqdata[_i].lasttime.tv_sec = \
(_seqset)->seqdata[_i].lasttime.tv_usec = 0; \
(_seqset)->seqdata[_i].lasttime.tv_usec = 0L; \
} \
} while (0);
@ -2902,7 +2901,7 @@ static void summarise_blocks()
K_RUNLOCK(blocks_free);
if (!b_prev) {
wi_start = 0;
elapsed_start.tv_sec = elapsed_start.tv_usec = 0L;
DATE_ZERO(&elapsed_start);
prev_hi = 0;
} else {
DATA_BLOCKS(prev_blocks, b_prev);
@ -2921,7 +2920,7 @@ static void summarise_blocks()
copy_tv(&elapsed_start, &(prev_workinfo->createdate));
prev_hi = prev_blocks->height;
}
elapsed_finish.tv_sec = elapsed_finish.tv_usec = 0L;
DATE_ZERO(&elapsed_finish);
// Add up the sharesummaries, abort if any SUMMARY_NEW
looksharesummary.workinfoid = wi_finish;
@ -5121,7 +5120,7 @@ static void confirm_reload()
}
} else {
if (confirm_first_workinfoid == 0) {
start.tv_sec = start.tv_usec = 0;
DATE_ZERO(&start);
LOGWARNING("%s() no start workinfo found ... "
"using time 0", __func__);
} else {

23
src/ckdb.h

@ -55,7 +55,7 @@
#define DB_VLOCK "1"
#define DB_VERSION "1.0.2"
#define CKDB_VERSION DB_VERSION"-1.231"
#define CKDB_VERSION DB_VERSION"-1.232"
#define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -270,6 +270,8 @@ extern const tv_t date_eot;
#define DATE_BEGIN 1388620800L
extern const tv_t date_begin;
#define DATE_ZERO(_tv) (_tv)->tv_sec = (_tv)->tv_usec = 0L
#define BTC_TO_D(_amt) ((double)((_amt) / 100000000.0))
// argv -y - don't run in ckdb mode, just confirm sharesummaries
@ -592,8 +594,7 @@ enum cmd_values {
STRNCPY(_row->createby, _by); \
STRNCPY(_row->createcode, _code); \
STRNCPY(_row->createinet, _inet); \
_row->modifydate.tv_sec = 0; \
_row->modifydate.tv_usec = 0; \
DATE_ZERO(&(_row->modifydate)); \
_row->modifyby[0] = '\0'; \
_row->modifycode[0] = '\0'; \
_row->modifyinet[0] = '\0'; \
@ -615,8 +616,7 @@ enum cmd_values {
SET_CREATEBY(_list, _row->createby, _by); \
SET_CREATECODE(_list, _row->createcode, _code); \
SET_CREATEINET(_list, _row->createinet, _inet); \
_row->modifydate.tv_sec = 0; \
_row->modifydate.tv_usec = 0; \
DATE_ZERO(&(_row->modifydate)); \
SET_MODIFYBY(_list, _row->modifyby, EMPTY); \
SET_MODIFYCODE(_list, _row->modifycode, EMPTY); \
SET_MODIFYINET(_list, _row->modifyinet, EMPTY); \
@ -1496,6 +1496,10 @@ typedef struct blocks {
double diffmean;
double cdferl;
double luck;
// To save looking them up when needed
tv_t prevcreatedate; // non-DB field
tv_t blockcreatedate; // non-DB field
} BLOCKS;
#define ALLOC_BLOCKS 100
@ -2305,12 +2309,15 @@ extern double _blockhash_diff(char *hash, WHERE_FFL_ARGS);
extern void dsp_blocks(K_ITEM *item, FILE *stream);
extern cmp_t cmp_blocks(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_blocks(int32_t height, char *blockhash, K_TREE_CTX *ctx);
extern K_ITEM *find_blocks_new(K_ITEM *b_item, K_TREE_CTX *ctx);
extern K_ITEM *find_prev_blocks(int32_t height);
extern const char *blocks_confirmed(char *confirmed);
extern void zero_on_new_block();
extern void set_block_share_counters();
extern bool check_update_blocks_stats(tv_t *stats);
#define set_blockcreatedate(_h) _set_blockcreatedate(_h, WHERE_FFL_HERE)
extern bool _set_blockcreatedate(int32_t oldest_height, WHERE_FFL_ARGS);
#define set_prevcreatedate(_h) _set_prevcreatedate(_h, WHERE_FFL_HERE)
extern bool _set_prevcreatedate(int32_t oldest_height, WHERE_FFL_ARGS);
extern cmp_t cmp_miningpayouts(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_miningpayouts(int64_t payoutid, int64_t userid);
extern K_ITEM *first_miningpayouts(int64_t payoutid, K_TREE_CTX *ctx);
@ -2376,8 +2383,8 @@ extern K_ITEM *_find_create_userinfo(int64_t userid, bool lock, WHERE_FFL_ARGS);
#define userinfo_update(_s, _ss, _ms) _userinfo_update(_s, _ss, _ms, true, true)
extern void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary,
MARKERSUMMARY *markersummary, bool ss_sub, bool lock);
#define userinfo_block(_blocks, _isnew) _userinfo_block(_blocks, _isnew, true)
extern void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock);
#define userinfo_block(_blocks, _isnew, _delta) _userinfo_block(_blocks, _isnew, _delta, true)
extern void _userinfo_block(BLOCKS *blocks, enum info_type isnew, int delta, bool lock);
// ***
// *** PostgreSQL functions ckdb_dbio.c

78
src/ckdb_cmd.c

@ -1128,8 +1128,7 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id,
char tmp[1024];
char *buf, *desc, desc_buf[64];
size_t len, off;
int32_t height = -1;
tv_t first_cd = {0,0}, stats_tv = {0,0}, stats_tv2 = {0,0};
tv_t stats_tv = {0,0}, stats_tv2 = {0,0};
int rows, srows, tot, seq;
int64_t maxrows;
bool has_stats;
@ -1164,13 +1163,6 @@ redo:
b_item = last_in_ktree(blocks_root, ctx);
while (b_item && rows < (int)maxrows) {
DATA_BLOCKS(blocks, b_item);
/* For each block remember the initial createdate
* Reverse sort order the oldest expirydate is first
* which should be the 'n' record */
if (height != blocks->height) {
height = blocks->height;
copy_tv(&first_cd, &(blocks->createdate));
}
if (CURRENT(&(blocks->expirydate))) {
if (blocks->confirmed[0] == BLOCKS_ORPHAN ||
blocks->confirmed[0] == BLOCKS_REJECT) {
@ -1207,16 +1199,24 @@ redo:
snprintf(tmp, sizeof(tmp), "workername:%d=%s%c", rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
// When block was found
snprintf(tmp, sizeof(tmp),
"first"CDTRF":%d=%ld%c", rows,
first_cd.tv_sec, FLDSEP);
blocks->blockcreatedate.tv_sec, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
// Last time block was updated
snprintf(tmp, sizeof(tmp),
CDTRF":%d=%ld%c", rows,
blocks->createdate.tv_sec, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
// When previous valid block was found
snprintf(tmp, sizeof(tmp),
"prev"CDTRF":%d=%ld%c", rows,
blocks->prevcreatedate.tv_sec, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp),
"confirmed:%d=%s%cstatus:%d=%s%c", rows,
blocks->confirmed, FLDSEP, rows,
@ -1305,6 +1305,7 @@ redo:
"s_desc:%d=%s%c"
"s_height:%d=%d%c"
"s_"CDTRF":%d=%ld%c"
"s_prev"CDTRF":%d=%ld%c"
"s_diffratio:%d=%.8f%c"
"s_diffmean:%d=%.8f%c"
"s_cdferl:%d=%.8f%c"
@ -1312,7 +1313,8 @@ redo:
srows, seq, FLDSEP,
srows, desc, FLDSEP,
srows, (int)(blocks->height), FLDSEP,
srows, blocks->createdate.tv_sec, FLDSEP,
srows, blocks->blockcreatedate.tv_sec, FLDSEP,
srows, blocks->prevcreatedate.tv_sec, FLDSEP,
srows, blocks->diffratio, FLDSEP,
srows, blocks->diffmean, FLDSEP,
srows, blocks->cdferl, FLDSEP,
@ -1344,8 +1346,8 @@ redo:
snprintf(tmp, sizeof(tmp),
"s_rows=%d%cs_flds=%s%c",
srows, FLDSEP,
"s_seq,s_desc,s_height,s_"CDTRF",s_diffratio,s_diffmean,"
"s_cdferl,s_luck",
"s_seq,s_desc,s_height,s_"CDTRF",s_prev"CDTRF",s_diffratio,"
"s_diffmean,s_cdferl,s_luck",
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
@ -1353,8 +1355,8 @@ redo:
"rows=%d%cflds=%s%c",
rows, FLDSEP,
"seq,height,blockhash,nonce,reward,workername,first"CDTRF","
CDTRF",confirmed,status,info,statsconf,diffacc,diffinv,"
"shareacc,shareinv,elapsed,netdiff,diffratio,cdf,luck",
CDTRF",prev"CDTRF",confirmed,status,info,statsconf,diffacc,"
"diffinv,shareacc,shareinv,elapsed,netdiff,diffratio,cdf,luck",
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
@ -1706,8 +1708,7 @@ static char *cmd_percent(char *cmd, char *id, tv_t *now, USERS *users)
// Add up all user's worker stats to be divided into payout percentages
lookworkers.userid = users->userid;
lookworkers.workername[0] = '\0';
lookworkers.expirydate.tv_sec = 0;
lookworkers.expirydate.tv_usec = 0;
DATE_ZERO(&(lookworkers.expirydate));
w_look.data = (void *)(&lookworkers);
w_item = find_after_in_ktree(workers_root, &w_look, cmp_workers, w_ctx);
DATA_WORKERS_NULL(workers, w_item);
@ -1968,8 +1969,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
lookworkers.userid = users->userid;
lookworkers.workername[0] = '\0';
lookworkers.expirydate.tv_sec = 0;
lookworkers.expirydate.tv_usec = 0;
DATE_ZERO(&(lookworkers.expirydate));
w_look.data = (void *)(&lookworkers);
w_item = find_after_in_ktree(workers_root, &w_look, cmp_workers, w_ctx);
DATA_WORKERS_NULL(workers, w_item);
@ -1983,7 +1983,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
copy_tv(&last_share, &(workerstatus->last_share));
K_RUNLOCK(workerstatus_free);
} else
last_share.tv_sec = last_share.tv_usec = 0L;
DATE_ZERO(&last_share);
if (tvdiff(now, &last_share) < oldworkers) {
str_to_buf(workers->workername, reply, sizeof(reply));
@ -2021,7 +2021,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
w_elapsed = -1;
if (!ws_item) {
w_lastshare.tv_sec = 0;
w_lastshare.tv_sec = 0L;
w_lastdiff = w_diffacc =
w_diffinv = w_diffsta =
w_diffdup = w_diffhi =
@ -2029,7 +2029,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
w_shareinv = w_sharesta =
w_sharedup = w_sharehi =
w_sharerej = w_active_diffacc = 0;
w_active_start.tv_sec = 0;
w_active_start.tv_sec = 0L;
} else {
DATA_WORKERSTATUS(workerstatus, ws_item);
// It's bad to read possibly changing data
@ -4018,8 +4018,8 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
LOGDEBUG("%s(): height %"PRId32, __func__, height);
block_tv.tv_sec = block_tv.tv_usec = 0L;
cd.tv_sec = cd.tv_usec = 0L;
DATE_ZERO(&block_tv);
DATE_ZERO(&cd);
lookblocks.height = height + 1;
lookblocks.blockhash[0] = '\0';
INIT_BLOCKS(&b_look);
@ -4446,7 +4446,6 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id,
PAYMENTS *payments;
PAYOUTS *payouts;
BLOCKS lookblocks, *blocks;
tv_t block_tv = { 0L, 0L };
WORKINFO *bworkinfo, *workinfo;
char ndiffbin[TXT_SML+1];
double ndiff;
@ -4470,36 +4469,26 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id,
LOGDEBUG("%s(): height %"PRId32, __func__, height);
lookblocks.height = height + 1;
lookblocks.height = height;
lookblocks.blockhash[0] = '\0';
INIT_BLOCKS(&b_look);
b_look.data = (void *)(&lookblocks);
K_RLOCK(blocks_free);
b_item = find_before_in_ktree(blocks_root, &b_look, cmp_blocks, b_ctx);
b_item = find_after_in_ktree(blocks_root, &b_look, cmp_blocks, b_ctx);
K_RUNLOCK(blocks_free);
if (!b_item) {
K_RUNLOCK(blocks_free);
snprintf(reply, siz, "ERR.no block height %"PRId32, height);
snprintf(reply, siz, "ERR.no block height >= %"PRId32, height);
return strdup(reply);
}
DATA_BLOCKS(blocks, b_item);
while (b_item && blocks->height == height) {
if (blocks->confirmed[0] == BLOCKS_NEW)
copy_tv(&block_tv, &(blocks->createdate));
// Allow any state, but report it
if (CURRENT(&(blocks->expirydate)))
break;
b_item = prev_in_ktree(b_ctx);
DATA_BLOCKS_NULL(blocks, b_item);
}
K_RUNLOCK(blocks_free);
if (!b_item || blocks->height != height) {
snprintf(reply, siz, "ERR.no block height %"PRId32, height);
return strdup(reply);
}
if (block_tv.tv_sec == 0) {
snprintf(reply, siz, "ERR.block %"PRId32" missing '%s' record",
height,
blocks_confirmed(BLOCKS_NEW_STR));
if (blocks->blockcreatedate.tv_sec == 0) {
snprintf(reply, siz, "ERR.block %"PRId32" has 0 blockcreatedate",
height);
return strdup(reply);
}
if (!CURRENT(&(blocks->expirydate))) {
@ -4676,10 +4665,11 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id,
snprintf(tmp, sizeof(tmp), "begin_epoch=%ld%c",
workinfo->createdate.tv_sec, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
tv_to_buf(&block_tv, tv_buf, sizeof(tv_buf));
tv_to_buf(&(blocks->blockcreatedate), tv_buf, sizeof(tv_buf));
snprintf(tmp, sizeof(tmp), "block_stamp=%s%c", tv_buf, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "block_epoch=%ld%c", block_tv.tv_sec, FLDSEP);
snprintf(tmp, sizeof(tmp), "block_epoch=%ld%c",
blocks->blockcreatedate.tv_sec, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
tv_to_buf(&(payouts->lastshareacc), tv_buf, sizeof(tv_buf));
snprintf(tmp, sizeof(tmp), "end_stamp=%s%c", tv_buf, FLDSEP);

282
src/ckdb_data.c

@ -369,8 +369,7 @@ void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t s
long sec, nsec;
int c;
// Caller test for tv_sec=0 for failure
((tv_t *)data)->tv_sec = 0L;
((tv_t *)data)->tv_usec = 0L;
DATE_ZERO((tv_t *)data);
c = sscanf(fld, "%ld,%ld", &sec, &nsec);
if (c > 0) {
((tv_t *)data)->tv_sec = (time_t)sec;
@ -1474,8 +1473,7 @@ K_ITEM *first_workers(int64_t userid, K_TREE_CTX *ctx)
workers.userid = userid;
workers.workername[0] = '\0';
workers.expirydate.tv_sec = 0L;
workers.expirydate.tv_usec = 0L;
DATE_ZERO(&(workers.expirydate));
INIT_WORKERS(&look);
look.data = (void *)(&workers);
@ -1628,8 +1626,7 @@ K_ITEM *find_paymentaddresses_create(int64_t userid, K_TREE_CTX *ctx)
K_ITEM look, *item;
paymentaddresses.userid = userid;
paymentaddresses.createdate.tv_sec = 0;
paymentaddresses.createdate.tv_usec = 0;
DATE_ZERO(&(paymentaddresses.createdate));
paymentaddresses.payaddress[0] = '\0';
INIT_PAYMENTADDRESSES(&look);
@ -1849,8 +1846,7 @@ K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height)
* activationdate will all be the default value and not
* decide the outcome */
STRNCPY(optioncontrol.optionname, optionname);
optioncontrol.activationdate.tv_sec = 0L;
optioncontrol.activationdate.tv_usec = 0L;
DATE_ZERO(&(optioncontrol.activationdate));
optioncontrol.activationheight = OPTIONCONTROL_HEIGHT - 1;
optioncontrol.expirydate.tv_sec = default_expiry.tv_sec;
optioncontrol.expirydate.tv_usec = default_expiry.tv_usec;
@ -2045,8 +2041,8 @@ bool workinfo_age(int64_t workinfoid, char *poolinstance, char *by, char *code,
LOGDEBUG("%s(): age", __func__);
ss_first->tv_sec = ss_first->tv_usec =
ss_last->tv_sec = ss_last->tv_usec = 0;
DATE_ZERO(ss_first);
DATE_ZERO(ss_last);
*ss_count = *s_count = *s_diff = 0;
wi_item = find_workinfo(workinfoid, NULL);
@ -2142,8 +2138,7 @@ bool workinfo_age(int64_t workinfoid, char *poolinstance, char *by, char *code,
lookshares.workinfoid = workinfoid;
lookshares.userid = sharesummary->userid;
strcpy(lookshares.workername, sharesummary->workername);
lookshares.createdate.tv_sec = 0;
lookshares.createdate.tv_usec = 0;
DATE_ZERO(&(lookshares.createdate));
s_look.data = (void *)(&lookshares);
K_WLOCK(shares_free);
@ -2390,8 +2385,8 @@ void auto_age_older(int64_t workinfoid, char *poolinstance, char *by,
cmp_sharesummary_workinfoid, ctx);
DATA_SHARESUMMARY_NULL(sharesummary, ss_item);
ss_first_min.tv_sec = ss_first_min.tv_usec =
ss_last_max.tv_sec = ss_last_max.tv_usec = 0;
DATE_ZERO(&ss_first_min);
DATE_ZERO(&ss_last_max);
ss_count_tot = s_count_tot = s_diff_tot = 0;
found = false;
@ -2621,33 +2616,6 @@ K_ITEM *find_blocks(int32_t height, char *blockhash, K_TREE_CTX *ctx)
return find_in_ktree(blocks_root, &look, cmp_blocks, ctx);
}
/* Find the matching NEW block - requires K_RLOCK()
* This requires calling find_blocks() first to get ctx */
K_ITEM *find_blocks_new(K_ITEM *b_item, K_TREE_CTX *ctx)
{
BLOCKS *blocks, *blocks2;
K_ITEM *b2_item;
// Return what was passed in if it was NULL or was the NEW block
DATA_BLOCKS_NULL(blocks, b_item);
if (!b_item || blocks->confirmed[0] == BLOCKS_NEW)
return b_item;
// NEW should be after the non-NEW block
b2_item = next_in_ktree(ctx);
DATA_BLOCKS_NULL(blocks2, b2_item);
while (b2_item && blocks2->height == blocks->height &&
strcmp(blocks2->blockhash, blocks->blockhash) == 0) {
if (blocks2->confirmed[0] == BLOCKS_NEW)
return b2_item;
b2_item = next_in_ktree(ctx);
DATA_BLOCKS_NULL(blocks2, b2_item);
}
return NULL;
}
// Must be R or W locked before call
K_ITEM *find_prev_blocks(int32_t height)
{
@ -2660,8 +2628,7 @@ K_ITEM *find_prev_blocks(int32_t height)
* not NEW, blocks, which might not find the right one */
lookblocks.height = height;
lookblocks.blockhash[0] = '\0';
lookblocks.expirydate.tv_sec = 0L;
lookblocks.expirydate.tv_usec = 0L;
DATE_ZERO(&(lookblocks.expirydate));
INIT_BLOCKS(&look);
look.data = (void *)(&lookblocks);
@ -3020,6 +2987,184 @@ bool check_update_blocks_stats(tv_t *stats)
return true;
}
// Must be under K_WLOCK(blocks_free) when called except during DB load
bool _set_blockcreatedate(int32_t oldest_height, WHERE_FFL_ARGS)
{
K_TREE_CTX ctx[1];
BLOCKS *blocks;
K_ITEM *b_item;
int32_t height;
char blockhash[TXT_BIG+1];
char cd_buf[DATE_BUFSIZ];
tv_t createdate;
bool ok = true;
// No blocks?
if (blocks_store->count == 0)
return true;
height = 0;
blockhash[0] = '\0';
DATE_ZERO(&createdate);
b_item = last_in_ktree(blocks_root, ctx);
DATA_BLOCKS_NULL(blocks, b_item);
while (b_item && blocks->height >= oldest_height) {
// NEW will be first going back
if (blocks->confirmed[0] == BLOCKS_NEW) {
height = blocks->height;
STRNCPY(blockhash, blocks->blockhash);
copy_tv(&createdate, &(blocks->createdate));
}
if (blocks->height != height ||
strcmp(blocks->blockhash, blockhash) != 0) {
// Missing NEW
tv_to_buf(&(blocks->expirydate), cd_buf, sizeof(cd_buf));
LOGEMERG("%s() block %"PRId32"/%s/%s/%s has no '"
BLOCKS_NEW_STR "' prev was %"PRId32"/%s."
WHERE_FFL,
__func__,
blocks->height, blocks->blockhash,
blocks->confirmed, cd_buf,
height, blockhash, WHERE_FFL_PASS);
ok = false;
height = blocks->height;
STRNCPY(blockhash, blocks->blockhash);
// set a useable (incorrect) value
copy_tv(&createdate, &(blocks->createdate));
}
// Always update it
copy_tv(&(blocks->blockcreatedate), &createdate);
b_item = prev_in_ktree(ctx);
DATA_BLOCKS_NULL(blocks, b_item);
}
return ok;
}
// Must be under K_WLOCK(blocks_free) when called except during DB load
bool _set_prevcreatedate(int32_t oldest_height, WHERE_FFL_ARGS)
{
K_ITEM look, *b_item = NULL, *wi_item;
BLOCKS lookblocks, *blocks = NULL;
K_TREE_CTX b_ctx[1], wi_ctx[1];
WORKINFO *workinfo;
char curr_blockhash[TXT_BIG+1];
char cd_buf[DATE_BUFSIZ];
int32_t curr_height;
tv_t prev_createdate;
tv_t curr_createdate;
bool ok = true, currok = false;
// No blocks?
if (blocks_store->count == 0)
return true;
// Find first 'ok' block before oldest_height
lookblocks.height = oldest_height;
lookblocks.blockhash[0] = '\0';
DATE_ZERO(&(lookblocks.expirydate));
INIT_BLOCKS(&look);
look.data = (void *)(&lookblocks);
b_item = find_before_in_ktree(blocks_root, &look, cmp_blocks, b_ctx);
while (b_item) {
DATA_BLOCKS(blocks, b_item);
if (CURRENT(&(blocks->expirydate)) &&
blocks->confirmed[0] != BLOCKS_ORPHAN &&
blocks->confirmed[0] != BLOCKS_REJECT)
break;
b_item = prev_in_ktree(b_ctx);
}
// Setup prev_createdate
if (b_item) {
/* prev_createdate is the ok b_item (before oldest_height)
* _set_blockcreatedate() should always be called
* before calling _set_prevcreatedate() */
copy_tv(&prev_createdate, &(blocks->blockcreatedate));
/* Move b_item forward to the next block
* since we don't have the prev value for b_item and
* also don't need to update the b_item block */
curr_height = blocks->height;
STRNCPY(curr_blockhash, blocks->blockhash);
while (b_item && blocks->height == curr_height &&
strcmp(blocks->blockhash, curr_blockhash) == 0) {
b_item = next_in_ktree(b_ctx);
DATA_BLOCKS_NULL(blocks, b_item);
}
} else {
/* There's none before oldest_height, so instead use:
* 'Pool Start' = first workinfo createdate */
K_RLOCK(workinfo_free);
wi_item = first_in_ktree(workinfo_root, wi_ctx);
K_RUNLOCK(workinfo_free);
if (wi_item) {
DATA_WORKINFO(workinfo, wi_item);
copy_tv(&prev_createdate, &(workinfo->createdate));
} else {
/* Shouldn't be possible since this function is first
* called after workinfo is loaded and the workinfo
* for each block must exist - thus data corruption */
DATE_ZERO(&prev_createdate);
LOGEMERG("%s() DB/tree corruption - blocks exist but "
"no workinfo exist!"
WHERE_FFL,
__func__, WHERE_FFL_PASS);
ok = false;
}
b_item = first_in_ktree(blocks_root, b_ctx);
}
// curr_* is unset and will be set first time in the while loop
curr_height = 0;
curr_blockhash[0] = '\0';
DATE_ZERO(&curr_createdate);
currok = false;
while (b_item) {
DATA_BLOCKS(blocks, b_item);
// While the same block, keep setting it
if (blocks->height == curr_height &&
strcmp(blocks->blockhash, curr_blockhash) == 0) {
copy_tv(&(blocks->prevcreatedate), &prev_createdate);
} else {
// Next block - if currok then 'prev' becomes 'curr'
if (currok)
copy_tv(&prev_createdate, &curr_createdate);
// New curr - CURRENT will be first
if (!CURRENT(&(blocks->expirydate))) {
tv_to_buf(&(blocks->expirydate), cd_buf,
sizeof(cd_buf));
LOGEMERG("%s() block %"PRId32"/%s/%s/%s first "
"record is not CURRENT" WHERE_FFL,
__func__,
blocks->height, blocks->blockhash,
blocks->confirmed, cd_buf,
WHERE_FFL_PASS);
ok = false;
}
curr_height = blocks->height;
STRNCPY(curr_blockhash, blocks->blockhash);
copy_tv(&curr_createdate, &(blocks->blockcreatedate));
if (CURRENT(&(blocks->expirydate)) &&
blocks->confirmed[0] != BLOCKS_ORPHAN &&
blocks->confirmed[0] != BLOCKS_REJECT)
currok = true;
else
currok = false;
// Set it
copy_tv(&(blocks->prevcreatedate), &prev_createdate);
}
b_item = next_in_ktree(b_ctx);
}
return ok;
}
/* order by payoutid asc,userid asc,expirydate asc
* i.e. only one payout amount per block per user */
cmp_t cmp_miningpayouts(K_ITEM *a, K_ITEM *b)
@ -3063,8 +3208,7 @@ K_ITEM *first_miningpayouts(int64_t payoutid, K_TREE_CTX *ctx)
miningpayouts.payoutid = payoutid;
miningpayouts.userid = 0;
miningpayouts.expirydate.tv_sec = 0;
miningpayouts.expirydate.tv_usec = 0;
DATE_ZERO(&(miningpayouts.expirydate));
INIT_MININGPAYOUTS(&look);
look.data = (void *)(&miningpayouts);
@ -3216,8 +3360,7 @@ K_ITEM *find_payouts_wid(int64_t workinfoidend, K_TREE_CTX *ctx)
ctx = ctx0;
payouts.workinfoidend = workinfoidend+1;
payouts.expirydate.tv_sec = 0;
payouts.expirydate.tv_usec = 0;
DATE_ZERO(&(payouts.expirydate));
INIT_PAYOUTS(&look);
look.data = (void *)(&payouts);
@ -3319,9 +3462,9 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
PAYMENTS *payments;
WORKINFO *workinfo;
PAYOUTS *payouts, *payouts2;
BLOCKS *blocks, *blocks2;
BLOCKS *blocks;
USERS *users;
K_ITEM *p_item, *old_p_item, *b_item, *b2_item, *w_item, *wb_item;
K_ITEM *p_item, *old_p_item, *b_item, *w_item, *wb_item;
K_ITEM *u_item, *mu_item, *oc_item, *pay_item, *p2_item, *old_p2_item;
SHARESUMMARY looksharesummary, *sharesummary;
WORKMARKERS lookworkmarkers, *workmarkers;
@ -3369,28 +3512,16 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
// Check the block status
K_RLOCK(blocks_free);
b_item = find_blocks(height, blockhash, b_ctx);
K_RUNLOCK(blocks_free);
if (!b_item) {
K_RUNLOCK(blocks_free);
LOGERR("%s(): no block %"PRId32"/%s for payout",
__func__, height, blockhash);
goto oku;
}
DATA_BLOCKS(blocks, b_item);
b2_item = find_blocks_new(b_item, b_ctx);
K_RUNLOCK(blocks_free);
if (!b2_item) {
LOGEMERG("%s(): missing %s record for block %"PRId32
"/%"PRId64"/%s/%s/%"PRId64,
__func__, blocks_confirmed(BLOCKS_NEW_STR),
blocks->height, blocks->workinfoid,
blocks->workername, blocks->confirmed,
blocks->reward);
goto oku;
}
DATA_BLOCKS(blocks2, b2_item);
copy_tv(&end_tv, &(blocks2->createdate));
copy_tv(&end_tv, &(blocks->blockcreatedate));
if (!addr_cd)
addr_cd = &(blocks2->createdate);
addr_cd = &(blocks->blockcreatedate);
LOGDEBUG("%s(): block %"PRId32"/%"PRId64"/%s/%s/%"PRId64,
__func__, blocks->height, blocks->workinfoid,
@ -3421,11 +3552,11 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
// Get the PPLNS N values
K_RLOCK(optioncontrol_free);
oc_item = find_optioncontrol(PPLNSDIFFTIMES, &(blocks->createdate),
oc_item = find_optioncontrol(PPLNSDIFFTIMES, &(blocks->blockcreatedate),
height);
K_RUNLOCK(optioncontrol_free);
if (!oc_item) {
tv_to_buf(&(blocks->createdate), cd_buf, sizeof(cd_buf));
tv_to_buf(&(blocks->blockcreatedate), cd_buf, sizeof(cd_buf));
LOGEMERG("%s(): missing optioncontrol %s (%s/%"PRId32")",
__func__, PPLNSDIFFTIMES, cd_buf, blocks->height);
goto oku;
@ -3434,11 +3565,11 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
diff_times = atof(optioncontrol->optionvalue);
K_RLOCK(optioncontrol_free);
oc_item = find_optioncontrol(PPLNSDIFFADD, &(blocks->createdate),
oc_item = find_optioncontrol(PPLNSDIFFADD, &(blocks->blockcreatedate),
height);
K_RUNLOCK(optioncontrol_free);
if (!oc_item) {
tv_to_buf(&(blocks->createdate), cd_buf, sizeof(cd_buf));
tv_to_buf(&(blocks->blockcreatedate), cd_buf, sizeof(cd_buf));
LOGEMERG("%s(): missing optioncontrol %s (%s/%"PRId32")",
__func__, PPLNSDIFFADD, cd_buf, blocks->height);
goto oku;
@ -3489,7 +3620,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
end_workinfoid = sharesummary->workinfoid;
/* Add up all sharesummaries until >= diff_want
* also record the latest lastshare - that will be the end pplns time
* which will be >= blocks->createdate */
* which will be >= blocks->blockcreatedate */
while (total_diff < diff_want && ss_item) {
switch (sharesummary->complete[0]) {
case SUMMARY_CONFIRM:
@ -3692,7 +3823,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
bzero(payouts, sizeof(*payouts));
payouts->height = height;
STRNCPY(payouts->blockhash, blockhash);
copy_tv(&(payouts->blockcreatedate), &(blocks2->createdate));
copy_tv(&(payouts->blockcreatedate), &(blocks->blockcreatedate));
d64 = blocks->reward * 9 / 1000;
g64 = blocks->reward - d64;
payouts->minerreward = g64;
@ -4424,8 +4555,7 @@ static bool gen_workmarkers(PGconn *conn, MARKS *stt, bool after, MARKS *fin,
look.data = (void *)(&workinfo);
K_RLOCK(workinfo_free);
if (before) {
workinfo.expirydate.tv_sec = 0;
workinfo.expirydate.tv_usec = 0;
DATE_ZERO(&(workinfo.expirydate));
wi_fin_item = find_before_in_ktree(workinfo_root, &look,
cmp_workinfo, ctx);
while (wi_fin_item) {
@ -5021,7 +5151,7 @@ void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary,
}
// N.B. good blocks = blocks - (orphans + rejects)
void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock)
void _userinfo_block(BLOCKS *blocks, enum info_type isnew, int delta, bool lock)
{
USERINFO *row;
K_ITEM *item;
@ -5031,12 +5161,12 @@ void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock)
if (lock)
K_WLOCK(userinfo_free);
if (isnew == INFO_NEW) {
row->blocks++;
row->blocks += delta;
copy_tv(&(row->last_block), &(blocks->createdate));
} else if (isnew == INFO_ORPHAN)
row->orphans++;
row->orphans += delta;
else if (isnew == INFO_REJECT)
row->rejects++;
row->rejects += delta;
if (lock)
K_WUNLOCK(userinfo_free);

106
src/ckdb_dbio.c

@ -1079,11 +1079,11 @@ K_ITEM *useratts_add(PGconn *conn, char *username, char *attname,
else
TXT_TO_BIGINT("attnum2", attnum2, row->attnum2);
if (attdate == NULL || attdate[0] == '\0')
row->attdate.tv_sec = row->attdate.tv_usec = 0L;
DATE_ZERO(&(row->attdate));
else
TXT_TO_TV("attdate", attdate, row->attdate);
if (attdate2 == NULL || attdate2[0] == '\0')
row->attdate2.tv_sec = row->attdate2.tv_usec = 0L;
DATE_ZERO(&(row->attdate2));
else
TXT_TO_TV("attdate2", attdate2, row->attdate2);
@ -2922,7 +2922,8 @@ bool workinfo_fill(PGconn *conn)
if (!ok) {
free_workinfo_data(item);
k_add_head(workinfo_free, item);
}
} else
ok = set_prevcreatedate(0);
//K_WUNLOCK(workinfo_free);
PQclear(res);
@ -4299,6 +4300,7 @@ unparam:
blocks_root = add_to_ktree(blocks_root, b_item, cmp_blocks);
k_add_head(blocks_store, b_item);
blocks_stats_rebuild = true;
// 'confirmed' is unchanged so no need to recalc *createdate
}
K_WUNLOCK(blocks_free);
@ -4439,7 +4441,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
}
// We didn't use a Begin
ok = true;
userinfo_block(row, INFO_NEW);
userinfo_block(row, INFO_NEW, 1);
goto unparam;
break;
case BLOCKS_ORPHAN:
@ -4598,10 +4600,49 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
}
update_old = true;
if (confirmed[0] == BLOCKS_ORPHAN)
userinfo_block(row, INFO_ORPHAN);
else if (confirmed[0] == BLOCKS_REJECT)
userinfo_block(row, INFO_REJECT);
/* handle confirmed state changes for userinfo
* this case statement handles all possible combinations
* even if they can't happen (yet) */
switch (oldblocks->confirmed[0]) {
case BLOCKS_ORPHAN:
switch (confirmed[0]) {
case BLOCKS_ORPHAN:
break;
case BLOCKS_REJECT:
userinfo_block(row, INFO_ORPHAN, -1);
userinfo_block(row, INFO_REJECT, 1);
break;
default:
userinfo_block(row, INFO_ORPHAN, -1);
break;
}
break;
case BLOCKS_REJECT:
switch (confirmed[0]) {
case BLOCKS_REJECT:
break;
case BLOCKS_ORPHAN:
userinfo_block(row, INFO_REJECT, -1);
userinfo_block(row, INFO_ORPHAN, 1);
break;
default:
userinfo_block(row, INFO_REJECT, -1);
break;
}
break;
default:
switch (confirmed[0]) {
case BLOCKS_ORPHAN:
userinfo_block(row, INFO_ORPHAN, 1);
break;
case BLOCKS_REJECT:
userinfo_block(row, INFO_REJECT, 1);
break;
default:
break;
}
break;
}
break;
default:
LOGERR("%s(): %s.failed.invalid confirm='%s'",
@ -4639,6 +4680,9 @@ flail:
blocks_root = add_to_ktree(blocks_root, b_item, cmp_blocks);
k_add_head(blocks_store, b_item);
blocks_stats_rebuild = true;
// recalc the *createdate fields for possibly affected blocks
set_blockcreatedate(row->height);
set_prevcreatedate(row->height);
}
K_WUNLOCK(blocks_free);
@ -4712,6 +4756,7 @@ bool blocks_fill(PGconn *conn)
{
ExecStatusType rescode;
PGresult *res;
K_TREE_CTX ctx[1];
K_ITEM *item;
int n, i;
BLOCKS *row;
@ -4863,16 +4908,30 @@ bool blocks_fill(PGconn *conn)
pool.height = row->height;
}
if (CURRENT(&(row->expirydate))) {
_userinfo_block(row, INFO_NEW, false);
if (row->confirmed[0] == BLOCKS_ORPHAN)
_userinfo_block(row, INFO_ORPHAN, false);
else if (row->confirmed[0] == BLOCKS_REJECT)
_userinfo_block(row, INFO_REJECT, false);
}
// first add all the NEW blocks
if (row->confirmed[0] == BLOCKS_NEW)
_userinfo_block(row, INFO_NEW, 1, false);
}
if (!ok)
k_add_head(blocks_free, item);
else
ok = set_blockcreatedate(0);
// Now update all the CURRENT orphan/reject stats
if (ok) {
item = first_in_ktree(blocks_root, ctx);
while (item) {
DATA_BLOCKS(row, item);
if (CURRENT(&(row->expirydate))) {
if (row->confirmed[0] == BLOCKS_ORPHAN)
_userinfo_block(row, INFO_ORPHAN, 1, false);
else if (row->confirmed[0] == BLOCKS_REJECT)
_userinfo_block(row, INFO_REJECT, 1, false);
}
item = next_in_ktree(ctx);
}
}
K_WUNLOCK(blocks_free);
PQclear(res);
@ -5506,7 +5565,7 @@ bool payouts_fill(PGconn *conn)
{
ExecStatusType rescode;
PGresult *res;
K_ITEM *item, *b_item, *b2_item;
K_ITEM *item, *b_item;
K_TREE_CTX ctx[1];
PAYOUTS *row;
BLOCKS *blocks;
@ -5633,17 +5692,10 @@ bool payouts_fill(PGconn *conn)
ok = false;
break;
} else {
b2_item = find_blocks_new(b_item, ctx);
if (!b2_item) {
LOGERR("%s(): payoutid %"PRId64" references "
"block %"PRId32"/%s that has no NEW",
__func__, row->payoutid, row->height,
row->blockhash);
ok = false;
break;
}
DATA_BLOCKS(blocks, b2_item);
copy_tv(&(row->blockcreatedate), &(blocks->createdate));
// blockcreatedate will already be set
DATA_BLOCKS(blocks, b_item);
copy_tv(&(row->blockcreatedate),
&(blocks->blockcreatedate));
}
payouts_root = add_to_ktree(payouts_root, item, cmp_payouts);

Loading…
Cancel
Save