Browse Source

Merge branch 'master' into multiproxy

master
Con Kolivas 10 years ago
parent
commit
0121d373cb
  1. 45
      pool/db.php
  2. 141
      pool/page.php
  3. 4
      pool/page_payments.php
  4. 7
      pool/page_pplns2.php
  5. 90
      pool/page_psperf.php
  6. 9
      pool/page_shifts.php
  7. 3
      pool/page_userset.php
  8. 78
      pool/page_usperf.php
  9. 21
      pool/page_workers.php
  10. 33
      pool/page_workmgt.php
  11. 5
      pool/prime.php
  12. 145
      src/ckdb.c
  13. 106
      src/ckdb.h
  14. 564
      src/ckdb_cmd.c
  15. 268
      src/ckdb_data.c
  16. 1044
      src/ckdb_dbio.c
  17. 88
      src/stratifier.c

45
pool/db.php

@ -110,6 +110,18 @@ function zeip()
return $_SERVER['REMOTE_ADDR']; return $_SERVER['REMOTE_ADDR'];
} }
# #
# user administration overrided
function adm($user, &$msg)
{
global $fld_sep, $val_sep;
if ($user == 'Kano')
{
$admin = getparam('admin', true);
if (!nuem($admin))
$msg .= $fld_sep . 'admin' . $val_sep . $admin;
}
}
#
function fldEncode($flds, $name, $first) function fldEncode($flds, $name, $first)
{ {
global $fld_sep, $val_sep; global $fld_sep, $val_sep;
@ -134,6 +146,7 @@ function msgEncode($cmd, $id, $fields, $user)
$msg .= 'createcode' . $val_sep . 'php' . $fld_sep; $msg .= 'createcode' . $val_sep . 'php' . $fld_sep;
$msg .= 'createby' . $val_sep . $user . $fld_sep; $msg .= 'createby' . $val_sep . $user . $fld_sep;
$msg .= 'createinet' . $val_sep . zeip(); $msg .= 'createinet' . $val_sep . zeip();
adm($user, $msg);
return $msg; return $msg;
} }
# #
@ -309,11 +322,13 @@ function getMPayouts($user)
return repDecode($rep); return repDecode($rep);
} }
# #
function getShifts($user) function getShifts($user, $workers = null)
{ {
if ($user == false) if ($user == false)
showIndex(); showIndex();
$flds = array('username' => $user); $flds = array('username' => $user);
if ($workers !== null)
$flds['select'] = $workers;
$msg = msgEncode('shifts', 'shift', $flds, $user); $msg = msgEncode('shifts', 'shift', $flds, $user);
$rep = sendsockreply('getShifts', $msg); $rep = sendsockreply('getShifts', $msg);
if (!$rep) if (!$rep)
@ -321,11 +336,13 @@ function getShifts($user)
return repDecode($rep); return repDecode($rep);
} }
# #
function getShiftData($user) function getShiftData($user, $workers = null)
{ {
if ($user == false) if ($user == false)
showIndex(); showIndex();
$flds = array('username' => $user); $flds = array('username' => $user);
if ($workers !== null)
$flds['select'] = $workers;
$msg = msgEncode('shifts', 'shift', $flds, $user); $msg = msgEncode('shifts', 'shift', $flds, $user);
$rep = sendsockreply('getShifts', $msg); $rep = sendsockreply('getShifts', $msg);
if (!$rep) if (!$rep)
@ -333,6 +350,30 @@ function getShiftData($user)
return repData($rep); return repData($rep);
} }
# #
function getPShifts($user)
{
if ($user == false)
showIndex();
$flds = array('username' => $user);
$msg = msgEncode('pshift', 'pshift', $flds, $user);
$rep = sendsockreply('getPShifts', $msg);
if (!$rep)
dbdown();
return repDecode($rep);
}
#
function getPShiftData($user)
{
if ($user == false)
showIndex();
$flds = array('username' => $user);
$msg = msgEncode('pshift', 'pshift', $flds, $user);
$rep = sendsockreply('getPShifts', $msg);
if (!$rep)
dbdown();
return repData($rep);
}
#
function getBlocks($user) function getBlocks($user)
{ {
if ($user == false) if ($user == false)

141
pool/page.php

@ -3,10 +3,12 @@
global $site_title; global $site_title;
global $page_title; global $page_title;
global $page_scripts; global $page_scripts;
global $page_css;
# #
$site_title = 'CKPool'; $site_title = 'CKPool';
$page_title = $site_title; $page_title = $site_title;
$page_scripts = ''; $page_scripts = '';
$page_css = '';
# #
global $dont_trm; global $dont_trm;
$dont_trm = false; $dont_trm = false;
@ -40,13 +42,18 @@ function addScript($script)
} }
} }
# #
function addCSS($css)
{
global $page_css;
$page_css .= $css;
}
#
function addGBase() function addGBase()
{ {
$g = "function hasCan(){var c0=document.getElementById('can0');c=document.getElementById('can');return !!(c0&&c&&c.getContext&&c.getContext('2d'));} $g = "function hasCan(){var c0=document.getElementById('can0');c=document.getElementById('can');return !!(c0&&c&&c.getContext&&c.getContext('2d'));}
function sep(d){ans={};var ar=d.split('\\t');var l=ar.length;for(var i=0;i<l;i++){var e=ar[i].indexOf('=');ans[ar[i].substr(0,e)]=ar[i].substr(e+1)};return ans} function sep(d){ans={};var ar=d.split('\\t');var l=ar.length;for(var i=0;i<l;i++){var e=ar[i].indexOf('=');ans[ar[i].substr(0,e)]=ar[i].substr(e+1)};return ans}
function dfmt(c,e){var d=new Date(e*1000);var DD,HH,MM;if(c['utc']){DD=d.getUTCDate();HH=d.getUTCHours();MM=d.getUTCMinutes()}else{DD=d.getDate();HH=d.getHours();MM=d.getMinutes()}var ans=''+DD+'/';if(HH<10){ans+='0'}ans+=''+HH+':';if(MM<10){ans+='0'}ans+=''+MM;return ans} function dfmt(c,e){var d=new Date(e*1000);var DD,HH,MM;if(c['utc']){DD=d.getUTCDate();HH=d.getUTCHours();MM=d.getUTCMinutes()}else{DD=d.getDate();HH=d.getHours();MM=d.getMinutes()}var ans=''+DD+'/';if(HH<10){ans+='0'}ans+=''+HH+':';if(MM<10){ans+='0'}ans+=''+MM;return ans}
function gcn(n){var ans='',d=document.cookie;if(d){var c0=d.indexOf(n+'='),cs=d.indexOf(' '+n+'=');if(c0==0||cs>0){if(cs>0){c0=cs+1}var c=d.substr(c0).split(';',1);var e=c[0].indexOf('=');if(e>0){ans=c[0].substr(e+1)}}}return ans}
function scnv(n,v){var d = new Date();d.setTime(d.getTime()+(864*Math.pow(10,8)));document.cookie=n+'='+v+'; expires='+d.toUTCString()+'; path=/'}
function ccb(c,n){var e=document.getElementById(n);c[n]=(e&&e.checked)} function ccb(c,n){var e=document.getElementById(n);c[n]=(e&&e.checked)}
function gch(z,zm){if(z<0.5){return 0.5}if(z>(zm-0.5)){return(zm-0.5)}return z} function gch(z,zm){if(z<0.5){return 0.5}if(z>(zm-0.5)){return(zm-0.5)}return z}
function gchx(c,x){return gch(x*c['xm']+c['xo'],c['ctx'].canvas.width)} function gchx(c,x){return gch(x*c['xm']+c['xo'],c['ctx'].canvas.width)}
@ -69,7 +76,7 @@ function gfl(c){c['ctx'].fill()}
function gst(c){c['ctx'].stroke()} function gst(c){c['ctx'].stroke()}
function gfi(c){gle(c);gst(c)} function gfi(c){gle(c);gst(c)}
function gbd(c){gbe(c,0,0);gln(c,1,0);gln(c,1,1);gln(c,0,1);gle(c);gfl(c);gst(c)} function gbd(c){gbe(c,0,0);gln(c,1,0);gln(c,1,1);gln(c,0,1);gle(c);gfl(c);gst(c)}
function ggr(c,xs,ys,yt,xn,x0,x1,y0,y1,ar,nx,vx,vy,av){ function ggr(c,xs,ys,yt,xn,x0,x1,y0,y1,ar,nx,vx,vy,av,w,cols){
gtso(c,xs,ys); gtso(c,xs,ys);
gss(c,'black');glw(c,1.5); gss(c,'black');glw(c,1.5);
gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c); gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c);
@ -78,40 +85,63 @@ var hi=c['ctx'].measureText('M').width, wi=c['ctx'].measureText('1').width;
for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')} for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')}
gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left'); gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left');
var m=Math.round(0.5+xn/20.0); var m=Math.round(0.5+xn/20.0);
var f=1;
for(var i=0;i<xn;i++){var n=ar[nx+i];var x=ar[vx+i];var xo=(x-x0)/(x1-x0);if(c['skey']&&(i<(xn-1))&&(i%m)==0){gbe(c,xo,0);gln(c,xo,-0.01);gst(c);gfz(c,xo,0,0,-hi*1.5,n,'#00a050','center')}if(c['slines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}} for(var i=0;i<xn;i++){var n=ar[nx+i];var x=ar[vx+i];var xo=(x-x0)/(x1-x0);if(c['skey']&&(i<(xn-1))&&(i%m)==0){gbe(c,xo,0);gln(c,xo,-0.01);gst(c);gfz(c,xo,0,0,-hi*1.5,n,'#00a050','center')}if(c['slines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}}
var xhr=x1-(x1%3600); var xhr=3600+x1-(x1%3600);
gss(c,'brown'); gss(c,'brown');
if(c['tkey']||c['tlines']){var hlv=c['hln'][c['hl']];hrs=c['hrs'][c['hr']]*3600/hlv; if(c['tkey']||c['tlines']){var hlv=c['hln'][c['hl']];hrs=c['hrs'][c['hr']]*3600/hlv;
var l=0;tpos=2.7;if(c['over']){tpos=1.5} var l=0;tpos=2.7;if(c['over']){tpos=1.5}
for(var i=xhr;i>=x0;i-=hrs){var n=dfmt(c,i);var xo=(i-x0)/(x1-x0);if(c['tkey']&&((l%hlv)==0)){gbe(c,xo,0);gln(c,xo,-0.02);gst(c);gfz(c,xo,0,0,-hi*tpos,n,'brown','center')}if(c['tlines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}l++}} for(var i=xhr;i>=x0;i-=hrs){var n=dfmt(c,i);var xo=(i-x0)/(x1-x0);if(xo<=1&&c['tkey']&&((l%hlv)==0)){gbe(c,xo,0);gln(c,xo,-0.02);gst(c);gfz(c,xo,0,0,-hi*tpos,n,'brown','center')}if(xo<=1&&c['tlines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}l++}}
glw(c,1); glw(c,1);
gss(c,'#0000c0'); if(c['smooth']){for(var j=1;j<w.length;j++){var f=1;gss(c,cols[j-1]);
if(c['smooth']){var xa=0,ya=0,xb=0,yb=0; var xa=0,ya=0,xb=0,yb=0;
for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0;xb=xo;yb=yo}else{gct(c,(xa+xb)/2,(ya+yb)/2,xb,yb,(xb+xo)/2,(yb+yo)/2)}xa=xb;ya=yb;xb=xo;yb=yo}gct(c,(xa+xb)/2,(ya+yb)/2,xo,yo,xo,yo);gst(c);} for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[w[j]+vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0;xb=xo;yb=yo}else{gct(c,(xa+xb)/2,(ya+yb)/2,xb,yb,(xb+xo)/2,(yb+yo)/2)}xa=xb;ya=yb;xb=xo;yb=yo}gct(c,(xa+xb)/2,(ya+yb)/2,xo,yo,xo,yo);gst(c);}}
else{for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0}else{gln(c,xo,yo)}}gst(c);} else{for(var j=1;j<w.length;j++){var f=1;gss(c,cols[j-1]);
for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[w[j]+vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0}else{gln(c,xo,yo)}}gst(c);}}
glw(c,1); glw(c,1);
gss(c,'red'); for(var j=1;j<w.length;j++){if(av[j-1]>0){gss(c,'red');var y=(av[j-1]-y0)/(y1-y0);gbe(c,0,y);gln(c,1,y);gst(c);
var y=(av-y0)/(y1-y0); var t=''+av[j-1].toFixed(2)+'av';gfz(c,1,y,1,0,t,cols[j-1],'left')}}
gbe(c,0,y);gln(c,1,y);gst(c);
var t=''+av.toFixed(2)+'av';gfz(c,1,y,1,0,t,'red','left')
if(c['tkey']){var col,hrl=c['hrs'].length;for(var i=0;i<hrl;i++){if(c['hr']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+1)*2,''+c['hrs'][i],col,'end')}for(var i=0;i<c['hln'].length;i++){if(c['hl']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+2+hrl)*2,''+c['hrs'][i],col,'end')}} if(c['tkey']){var col,hrl=c['hrs'].length;for(var i=0;i<hrl;i++){if(c['hr']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+1)*2,''+c['hrs'][i],col,'end')}for(var i=0;i<c['hln'].length;i++){if(c['hl']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+2+hrl)*2,''+c['hrs'][i],col,'end')}}
} }
function sn(i,shi){if(shi.indexOf(' Shift ')<0){return ''+(i%10)}else{return shi.replace(/.* ([a-z])[a-z]*$/,'$1')}} function sn(i,shi){if(shi.indexOf(' Shift ')<0){return ''+(i%10)}else{return shi.replace(/.* ([a-z])[a-z]*$/,'$1')}}
function gc(c){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.round(c['wx']*0.9+0.5);c['ym']=Math.round(c['wy']*0.8+0.5);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);c['pxe']=Math.max(Math.round(c['xm']/250),1)} function gc(c){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.max(Math.round(c['wx']*0.9+0.5),400);c['ym']=Math.max(Math.round(c['wy']*0.8+0.5),400);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);c['pxe']=Math.max(Math.round(c['xm']/250),1)}
function opts(t,i){var e=document.getElementById(i);if(t.checked){e.style.visibility='visible'}else{e.style.visibility='hidden'}} function opts(t,i){var e=document.getElementById(i);if(t.checked){e.style.visibility='visible'}else{e.style.visibility='hidden'}}
function ghrs(c){c['hrs']=[1,2,3,4,6,8,12,24];c['hln']=[1,2,3,4,6]} function ghrs(c){c['hrs']=[1,2,3,4,6,8,12,24,48];c['hln']=[1,2,3,4,6]}
function gopt(c,cbx){for(var i=0;i<cbx.length;i++){ccb(c,cbx[i])}c['hr']=4;c['hl']=0} function ghg(c,dx){var tl=dx/(gchx(c,1)/50)/3600;for(var j=c['hrs'].length-1;j>=0;j--){if(tl<c['hrs'][j]){c['hr']=j}else{break}}if(tl<0.5){var tb=1/tl;for(var k=0;k<c['hln'].length;k++){if(c['hln'][k]<tb){c['hl']=k}else{break}}}else{c['hl']=1}}
function gopt(c,cbx){for(var i=0;i<cbx.length;i++){ccb(c,cbx[i])}}
function doinit(cbx,xon){for(var i=0;i<cbx.length;i++){var e=document.getElementById(cbx[i]);if(e){var n=gcn(cbx[i]);if(n==''){if(xon[cbx[i]]){e.checked=true}else{e.checked=false}}else{if(n=='1'){e.checked=true}else{e.checked=false}}}}} function doinit(cbx,xon){for(var i=0;i<cbx.length;i++){var e=document.getElementById(cbx[i]);if(e){var n=gcn(cbx[i]);if(n==''){if(xon[cbx[i]]){e.checked=true}else{e.checked=false}}else{if(n=='1'){e.checked=true}else{e.checked=false}}}}}
"; ";
addScript($g); addScript($g);
} }
# #
function makeLink($page, $rest = '') function addTips()
{ {
if ($page != '') $t = "function untip(e){if(e){if(typeof e.tmo!='undefined'){clearTimeout(e.tmo);delete e.tmo}e.style.opacity=0;e.style.visibility='hidden'}}
function tip(i,n){var e=document.getElementById(i);if(e){if(e.style.visibility=='visible'){untip(e)}else{e.style.visibility='visible';e.style.opacity=0.95;e.tmo=setTimeout(function(){untip(e)},n)}}}
";
addScript($t);
$tcss = "span.tip0 {position:absolute;z-index:42;pointer-events:none;font-size:smaller;text-align:left;}
span.notip {position:relative;color:#0077ee;background:#bbffff;border-style:solid;border-color:black;border-width:1px;left:-10px;width:200px;padding:2px;float:left;transition:visibility 0.5s,opacity 0.5s;visibility:hidden;opacity:0}
span.tip {visibility: visibile;}
span.q {position: relative; width: 16px; height: 16px; display: inline-block; background-color: #0077ee; line-height: 16px; color: White; font-size: 13px; font-weight: bold; border-radius: 8px; text-align: center; cursor: pointer; }
ul.tip {margin-top:0;margin-bottom:0;list-style:disc inside none;margin-left:0;padding-left:0.5em;display:block}
li {padding-left:0.5em;}
";
addCSS($tcss);
}
#
#
function makeURL($page)
{
if ($page == null)
$page = '';
else if ($page != '')
$page = '?k='.$page; $page = '?k='.$page;
$href = "<a href='index.php$page'"; return "/index.php$page";
}
function makeLink($page, $rest = '')
{
$href = "<a href='".makeURL($page)."'";
if ($rest != '') if ($rest != '')
$href .= " $rest"; $href .= " $rest";
$href .= '>'; $href .= '>';
@ -147,11 +177,19 @@ function trm_force($html)
return dotrm($html, false); return dotrm($html, false);
} }
# #
function pghead($script_marker, $name) function isCrap()
{
if (isset($_SERVER['HTTP_USER_AGENT']))
return strpos($_SERVER['HTTP_USER_AGENT'],'iP');
else
return false;
}
#
function pghead($css_marker, $script_marker, $name)
{ {
global $page_title; global $page_title;
$iCrap = strpos($_SERVER['HTTP_USER_AGENT'],'iP'); $iCrap = isCrap();
$head = "<!DOCTYPE html>\n"; $head = "<!DOCTYPE html>\n";
@ -160,12 +198,18 @@ function pghead($script_marker, $name)
$head .= "<meta content='IE=edge' http-equiv='X-UA-Compatible'>"; $head .= "<meta content='IE=edge' http-equiv='X-UA-Compatible'>";
$head .= "<meta content='width=device-width, initial-scale=1' name='viewport'>"; $head .= "<meta content='width=device-width, initial-scale=1' name='viewport'>";
$head .= "<script type='text/javascript'>\n"; $head .= "<script type='text/javascript'>
$head .= "function jst(){document.getElementById('jst').style.visibility='hidden';}\n"; function gcn(n){var ans='',d=document.cookie;if(d){var c0=d.indexOf(n+'='),cs=d.indexOf(' '+n+'=');if(c0==0||cs>0){if(cs>0){c0=cs+1}var c=d.substr(c0).split(';',1);var e=c[0].indexOf('=');if(e>0){ans=c[0].substr(e+1)}}}return ans}
$head .= "window.onpaint=jst();\n</script>\n"; function scnv(n,v){var d=new Date();d.setTime(d.getTime()+(864*Math.pow(10,8)));document.cookie=n+'='+v+'; expires='+d.toUTCString()+'; path=/'}
function ni(e,o){if(e){if(o==0){e.defd=e.style.display;e.style.display='none'}else{e.style.display=e.defd}}}
function domin(o){var e=document.getElementById('minicb');if(e){if(o==0){e.checked=true}else{e.checked=false}};for(var i=0;i<10;i++){e=document.getElementById('mini'+i);ni(e,o)}}
function mini(){var hm=gcn('mini');if(hm==''){domin(1)}else{domin(0)}}
function md(e){var c='';if(e.checked){c='y'}scnv('mini',c);mini()}
function jst(){var e=document.getElementById('jst');if(e){e.style.visibility='hidden'}}
window.onpaint=jst();
</script>\n";
$head .= "<style type='text/css'> $head .= "<style type='text/css'>
input {vertical-align: -2px;} input[type=checkbox] {vertical-align: -2px;}
form {display: inline-block;} form {display: inline-block;}
html, body {height: 100%; font-family:Arial, Verdana, sans-serif; font-size:12pt; background-color:#eeffff; text-align: center; background-repeat: no-repeat; background-position: center;} html, body {height: 100%; font-family:Arial, Verdana, sans-serif; font-size:12pt; background-color:#eeffff; text-align: center; background-repeat: no-repeat; background-position: center;}
.page {min-height: 100%; height: auto !important; height: 100%; margin: 0 auto -50px; position: relative;} .page {min-height: 100%; height: auto !important; height: 100%; margin: 0 auto -50px; position: relative;}
@ -176,6 +220,7 @@ div.topd {background-color:#cff; border-color: #cff; border-style: solid; border
.topdesl {color:blue; text-align: left;} .topdesl {color:blue; text-align: left;}
.topwho {color:black; font-weight: bold; margin-right: 8px;} .topwho {color:black; font-weight: bold; margin-right: 8px;}
.topdat {margin-left: 8px; margin-right: 24px; color:green; font-weight: bold;} .topdat {margin-left: 8px; margin-right: 24px; color:green; font-weight: bold;}
span.nb {white-space: pre;}
span.login {float: right; margin-left: 8px; margin-right: 24px;} span.login {float: right; margin-left: 8px; margin-right: 24px;}
span.hil {color:blue;} span.hil {color:blue;}
span.user {color:green;} span.user {color:green;}
@ -185,18 +230,18 @@ span.urg {color:red; font-weight:bold;}
span.err {color:red; font-weight:bold; font-size:120%;} span.err {color:red; font-weight:bold; font-size:120%;}
span.alert {color:red; font-weight:bold; font-size:250%;} span.alert {color:red; font-weight:bold; font-size:250%;}
input.tiny {width: 0px; height: 0px; margin: 0px; padding: 0px; outline: none; border: 0px;} input.tiny {width: 0px; height: 0px; margin: 0px; padding: 0px; outline: none; border: 0px;}
#n42 {margin:0; position: relative; color:#fff; background:#07e;} #n42 {margin:0; position: relative; color:#ffffff; background:#0077ee;}
#n42 a {color:#fff; text-decoration:none; padding: 6px; display:block;} #n42 a {color:#fff; text-decoration:none; padding: 6px; display:block;}
#n42 td {min-width: 100px; float: left; vertical-align: top; padding: 0px 2px;} #n42 td {min-width: 100px; float: left; vertical-align: top; padding: 0px 2px;}
#n42 td.navboxr {float: right;} #n42 td.navboxr {float: right;}
#n42 td.nav {position: relative;} #n42 td.nav {position: relative;}
#n42 td.ts {border-width: 1px; border-color: #02e; border-style: solid none none none;}"; #n42 td.ts {border-width: 1px; border-color: #0022ee; border-style: solid none none none;}";
if (!$iCrap) if (!$iCrap)
{ {
$head .= " $head .= "
#n42 div.sub {left: 0px; z-index: 42; position: absolute; visibility: hidden;} #n42 div.sub {left: 0px; z-index: 42; position: absolute; visibility: hidden;}
#n42 td.nav:hover {background:#09e;} #n42 td.nav:hover {background:#0099ee;}
#n42 td.nav:hover div.sub {background:#07e; visibility: visible;}"; #n42 td.nav:hover div.sub {background:#0077ee; visibility: visible;}";
} }
$head .= " $head .= "
h1 {margin-top: 20px; float:middle; font-size: 20px;} h1 {margin-top: 20px; float:middle; font-size: 20px;}
@ -218,6 +263,7 @@ h1 {margin-top: 20px; float:middle; font-size: 20px;}
.fthi {color:red; font-size:7px; } .fthi {color:red; font-size:7px; }
.ftlo {color:green; font-size:7px; } .ftlo {color:green; font-size:7px; }
.ft {color:blue; font-size:7px; } .ft {color:blue; font-size:7px; }
$css_marker
</style>\n"; </style>\n";
$head .= '<meta name="robots" content="noindex">'; $head .= '<meta name="robots" content="noindex">';
@ -279,7 +325,7 @@ function pgtop($info, $dotop, $user, $douser)
$min -= ($hr * 60); $min -= ($hr * 60);
$plb = $hr.'h'; $plb = $hr.'h';
if ($min > 0) if ($min > 0)
$plb .= ' '.$min.'m'; $plb .= '&nbsp;'.$min.'m';
} }
} }
} }
@ -298,7 +344,7 @@ function pgtop($info, $dotop, $user, $douser)
$nlb = $min.'m'; $nlb = $min.'m';
$s = $sec - $min * 60; $s = $sec - $min * 60;
if ($s > 0) if ($s > 0)
$nlb .= " ${s}s"; $nlb .= "&nbsp;${s}s";
} }
} }
@ -352,9 +398,9 @@ function pgtop($info, $dotop, $user, $douser)
} }
} }
$top = "<div class=jst id=jst>&nbsp;Javascript isn't enabled."; $top = "<noscript><div class=jst id=jst>&nbsp;Javascript isn't enabled.";
$top .= " You need to enable javascript to use"; $top .= " You need to enable javascript to use";
$top .= " the $site_title web site.</div>"; $top .= " the $site_title web site.</div></noscript>";
if ($loginfailed === true) if ($loginfailed === true)
$top .= '<div class=accwarn>Login Failed</div>'; $top .= '<div class=accwarn>Login Failed</div>';
@ -406,18 +452,24 @@ function pgtop($info, $dotop, $user, $douser)
$lh = $img1.$lhc.$img2; $lh = $img1.$lhc.$img2;
$lw = $img1.$lwc.$img2; $lw = $img1.$lwc.$img2;
} }
if (!isset($info['users']))
$info['users'] = '?';
if (!isset($info['workers']))
$info['workers'] = '?';
$top .= '<table cellpadding=0 cellspacing=0 border=0 width=100%><tr><td>'; $top .= '<table cellpadding=0 cellspacing=0 border=0 width=100%><tr><td>';
$top .= '<table cellpadding=1 cellspacing=0 border=0>'; $top .= '<table cellpadding=1 cellspacing=0 border=0>';
$top .= "<tr><td class=topdes>$lh</td></tr>"; $top .= "<tr><td class=topdes>$lh</td></tr>";
$top .= "<tr><td class=topdes>$ls</td></tr>"; $top .= "<tr><td class=topdes>$ls</td></tr>";
$top .= "<tr><td class=topdes>$lw</td></tr></table>"; $top .= "<tr id=mini0><td class=topdes>$lw</td></tr></table>";
$top .= '</td><td>'; $top .= '</td><td>';
$top .= '<table cellpadding=1 cellspacing=0 border=0 width=100%>'; $top .= '<table cellpadding=1 cellspacing=0 border=0 width=100%>';
$top .= '<tr><td class=topdes>CKPool:&nbsp;</td>'; $top .= '<tr><td class=topdes>CKPool:&nbsp;</td>';
$top .= "<td class=topdat>&nbsp;$phr</td></tr>"; $top .= "<td class=topdat>&nbsp;$phr</td></tr>";
$top .= '<tr><td class=topdes>Shares:&nbsp;</td>'; $top .= '<tr><td class=topdes>Shares:&nbsp;</td>';
$top .= "<td class=topdat>&nbsp;$pac</td></tr>"; $top .= "<td class=topdat>&nbsp;$pac</td></tr>";
$top .= '<tr><td class=topdes>Invalid:&nbsp;</td>'; $top .= '<tr id=mini1><td class=topdes>Invalid:&nbsp;</td>';
$top .= "<td class=topdat>&nbsp;$per</td></tr></table>"; $top .= "<td class=topdat>&nbsp;$per</td></tr></table>";
$top .= '</td><td>'; $top .= '</td><td>';
$top .= '<table cellpadding=1 cellspacing=0 border=0 width=100%>'; $top .= '<table cellpadding=1 cellspacing=0 border=0 width=100%>';
@ -425,9 +477,9 @@ function pgtop($info, $dotop, $user, $douser)
$top .= '<td class=topdesl>Block</td></tr>'; $top .= '<td class=topdesl>Block</td></tr>';
$top .= '<tr><td class=topdes>Pool:&nbsp;</td>'; $top .= '<tr><td class=topdes>Pool:&nbsp;</td>';
$top .= "<td class=topdat>&nbsp;$plb</td></tr>"; $top .= "<td class=topdat>&nbsp;$plb</td></tr>";
$top .= '<tr><td class=topdes>Network:&nbsp;</td>'; $top .= '<tr id=mini2><td class=topdes>Network:&nbsp;</td>';
$top .= "<td class=topdat>&nbsp;$nlb</td></tr></table>"; $top .= "<td class=topdat>&nbsp;$nlb</td></tr></table>";
$top .= '</td><td>'; $top .= '</td><td id=mini3>';
$top .= '<table cellpadding=1 cellspacing=0 border=0 width=100%>'; $top .= '<table cellpadding=1 cellspacing=0 border=0 width=100%>';
$top .= '<tr><td class=topdes>Users:&nbsp;</td>'; $top .= '<tr><td class=topdes>Users:&nbsp;</td>';
$top .= '<td class=topdat>&nbsp;'.$info['users'].'</td></tr>'; $top .= '<td class=topdat>&nbsp;'.$info['users'].'</td></tr>';
@ -484,7 +536,7 @@ function pgtop($info, $dotop, $user, $douser)
# #
function pgmenu($menus) function pgmenu($menus)
{ {
$iCrap = strpos($_SERVER['HTTP_USER_AGENT'],'iP'); $iCrap = isCrap();
$ret = "\n<table cellpadding=0 cellspacing=0 border=0 width=100% id=n42>"; $ret = "\n<table cellpadding=0 cellspacing=0 border=0 width=100% id=n42>";
$ret .= '<tr><td width=100%>'; $ret .= '<tr><td width=100%>';
@ -537,7 +589,7 @@ function pgmenu($menus)
# #
function pgbody($info, $page, $menu, $dotop, $user, $douser) function pgbody($info, $page, $menu, $dotop, $user, $douser)
{ {
$body = '<body onload="jst()"'; $body = '<body onload="mini();jst()"';
if ($page == 'index') if ($page == 'index')
$body .= ' background=/BTC20.png'; $body .= ' background=/BTC20.png';
$body .= '><div class=page>'; $body .= '><div class=page>';
@ -590,9 +642,10 @@ function pgfoot($info)
function gopage($info, $data, $pagefun, $page, $menu, $name, $user, $ispage = true, $dotop = true, $douser = true) function gopage($info, $data, $pagefun, $page, $menu, $name, $user, $ispage = true, $dotop = true, $douser = true)
{ {
global $dbg, $stt; global $dbg, $stt;
global $page_scripts; global $page_css, $page_scripts;
$dbg_marker = '[@dbg@]'; $dbg_marker = '[@dbg@]';
$css_marker = '[@css@]';
$script_marker = '[@scripts@]'; $script_marker = '[@scripts@]';
if ($dbg === true) if ($dbg === true)
@ -614,13 +667,15 @@ function gopage($info, $data, $pagefun, $page, $menu, $name, $user, $ispage = tr
// if (isset($_SESSION['logkey'])) // if (isset($_SESSION['logkey']))
// unset($_SESSION['logkey']); // unset($_SESSION['logkey']);
$head = pghead($script_marker, $name); $head = pghead($css_marker, $script_marker, $name);
$body = pgbody($info, $page, $menu, $dotop, $user, $douser); $body = pgbody($info, $page, $menu, $dotop, $user, $douser);
$foot = pgfoot($info); $foot = pgfoot($info);
if ($dbg === true) if ($dbg === true)
$pg = str_replace($dbg_marker, cvtdbg(), $pg); $pg = str_replace($dbg_marker, cvtdbg(), $pg);
$head = str_replace($css_marker, $page_css, $head);
if ($page_scripts != '') if ($page_scripts != '')
$page_scripts .= "</script>"; $page_scripts .= "</script>";

4
pool/page_payments.php

@ -9,10 +9,12 @@ function dopayments($data, $user)
{ {
$bc = 'https://blockchain.info/address/'; $bc = 'https://blockchain.info/address/';
$addr1 = '1KzFJddTvK9TQWsmWFKYJ9fRx9QeSATyrT'; $addr1 = '1KzFJddTvK9TQWsmWFKYJ9fRx9QeSATyrT';
$addr2 = '16dRhawxuR3BmdmkzdzUdgEfGAQszgmtbc';
$pg = '<h1>Payments</h1>'; $pg = '<h1>Payments</h1>';
$pg .= 'The payment transactions on blockchain are here:'; $pg .= 'The payment transactions on blockchain are here:';
$pg .= " <a href='$bc$addr1' target=_blank>BTC</a><br>"; $pg .= " <a href='$bc$addr1' target=_blank>BTCa</a> and";
$pg .= " <a href='$bc$addr2' target=_blank>BTCb</a><br>";
$pg .= "The payments below don't yet show when they have been sent.<br><br>"; $pg .= "The payments below don't yet show when they have been sent.<br><br>";
$ans = getPayments($user); $ans = getPayments($user);

7
pool/page_pplns2.php

@ -222,13 +222,6 @@ Block: <input type=text name=blk size=10 value='$blkuse'>
$pg .= str_replace(' ', '&nbsp;', $msg)."</span><br>\n"; $pg .= str_replace(' ', '&nbsp;', $msg)."</span><br>\n";
} }
if (strlen($ans['share_status']) > 0)
{
$pg .= '<br><span class=err>';
$msg = $ans['share_status']." - Can't be paid out yet";
$pg .= str_replace(' ', '&nbsp;', $msg)."</span><br>\n";
}
$pg .= "<br><table callpadding=0 cellspacing=0 border=0>\n"; $pg .= "<br><table callpadding=0 cellspacing=0 border=0>\n";
$pg .= '<tr class=title>'; $pg .= '<tr class=title>';
$pg .= '<td class=dl>Name</td>'; $pg .= '<td class=dl>Name</td>';

90
pool/page_psperf.php

@ -0,0 +1,90 @@
<?php
#
function pspg($nc)
{
$g = "function gdrw(c,d,cbx){gc(c);ghrs(c);gopt(c,cbx);
gfs(c,'white');gss(c,'#0000c0');glw(c,2);gbd(c);
var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0,tda=[];
var w=d['arp'].split(',');var cols=d['cols'].split(',');
for(var j=1;j<w.length;j++){tda[j-1]=0}
for(var i=0;i<rows;i++){var s=parseFloat(d['start:'+i]);var e=parseFloat(d['end:'+i]);d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax<e){xmax=e}d['vx:'+i]=(s+e)/2.0;
for(var j=1;j<w.length;j++){var pre=w[j];var ths=0,nam=pre+'diffacc:'+i;if(d[nam]){var da=parseFloat(d[nam]);ths=(da/(e-s))*Math.pow(2,32)/Math.pow(10,12);tda[j-1]+=da}d[pre+'ths:'+i]=ths;if(ymin==-1||ymin>ths){ymin=ths}if(ths>ymax)ymax=ths}
}
for(var j=1;j<w.length;j++){tda[j-1]*=(Math.pow(2,32)/Math.pow(10,12)/(xmax-xmin))}
var p5=(ymax-ymin)*0.05;ymax+=p5;ymin-=p5;if(ymin<0){ymin=0}
if(c['zerob']){ymin=0}
ghg(c,xmax-xmin);
ggr(c,0.9,0.9,'TH/s',rows,xmin,xmax,ymin,ymax,d,'nx:','vx:','ths:',tda,w,cols)}
c={};
function dodrw(data,cbx){if(hasCan()){gdrw(c,sep(data),cbx)}}
function gact(t){if(t.checked){scnv(t.id,1)}else{scnv(t.id,0)}godrw(0)}";
return $g;
}
#
function dopsperf($data, $user)
{
global $fld_sep, $val_sep;
$cols = array('#0000c0');
$nc = count($cols);
$datacols = $cols[0];
$ans = getPShiftData($user);
$iCrap = strpos($_SERVER['HTTP_USER_AGENT'],'iP');
if ($iCrap)
$vlines = false;
else
$vlines = true;
$pg = '<h1>Pool Shift Reward Performance</h1><br>';
if ($ans['STATUS'] == 'ok' and $ans['DATA'] != '')
{
addGBase();
addTips();
$cbx = array('skey' => 'shift key', 'slines' => 'shift lines',
'tkey' => 'time key', 'tlines' => 'time lines',
'over' => 'key overlap', 'smooth' => 'smooth',
'zerob' => 'zero based', 'utc' => 'utc');
$xon = array('skey' => 1, 'utc' => 1);
if ($vlines === true)
$xon['slines'] = 1;
$pg .= "<div>";
foreach ($cbx as $nam => $txt)
{
$pg .= ' <span class=nb>';
$pg .= "<input type=checkbox id=$nam onclick='gact(this)'>";
$pg .= "$txt&nbsp;</span>";
}
$pg .= '</div>';
$pg .= '<div id=can0><canvas id=can width=1 height=1>';
$pg .= 'A graph will show here if your browser supports html5/canvas';
$pg .= "</canvas></div>\n";
$data = str_replace(array("\\","'"), array("\\\\","\\'"), $ans['DATA']);
$data .= $fld_sep . 'cols' . $val_sep . $datacols;
$pg .= "<script type='text/javascript'>\n";
$pg .= pspg($nc);
$pg .= "\nfunction godrw(f){var cbx=[";
$comma = '';
foreach ($cbx as $nam => $txt)
{
$pg .= "$comma'$nam'";
$comma = ',';
}
$pg .= '];if(f){var xon={};';
foreach ($xon as $nam => $val)
$pg .= "xon['$nam']=1;";
$pg .= "doinit(cbx,xon)}dodrw('$data',cbx)};godrw(1);</script>\n";
}
return $pg;
}
#
function show_psperf($info, $page, $menu, $name, $user)
{
gopage($info, NULL, 'dopsperf', $page, $menu, $name, $user);
}
#
?>

9
pool/page_shifts.php

@ -14,10 +14,13 @@ function doshifts($data, $user)
$pg .= "<td class=dr>Shares</td>"; $pg .= "<td class=dr>Shares</td>";
$pg .= "<td class=dr>Avg Share</td>"; $pg .= "<td class=dr>Avg Share</td>";
$pg .= "</tr>\n"; $pg .= "</tr>\n";
if ($ans['STATUS'] != 'ok')
if (($ans['STATUS'] != 'ok') || !isset($ans['prefix_all']))
$pg = '<h1>Shifts</h1>'.$pg; $pg = '<h1>Shifts</h1>'.$pg;
else else
{ {
$pre = $ans['prefix_all'];
$count = $ans['rows']; $count = $ans['rows'];
$pg = '<h1>Last '.($count+1).' Shifts</h1>'.$pg; $pg = '<h1>Last '.($count+1).' Shifts</h1>'.$pg;
for ($i = 0; $i < $count; $i++) for ($i = 0; $i < $count; $i++)
@ -49,11 +52,11 @@ function doshifts($data, $user)
$nd = $ans['end:'.$i]; $nd = $ans['end:'.$i];
$elapsed = $nd - $start; $elapsed = $nd - $start;
$pg .= '<td class=dr>'.howmanyhrs($elapsed).'</td>'; $pg .= '<td class=dr>'.howmanyhrs($elapsed).'</td>';
$diffacc = $ans['diffacc:'.$i]; $diffacc = $ans[$pre.'diffacc:'.$i];
$pg .= '<td class=dr>'.difffmt($diffacc).'</td>'; $pg .= '<td class=dr>'.difffmt($diffacc).'</td>';
$hr = $diffacc * pow(2,32) / $elapsed; $hr = $diffacc * pow(2,32) / $elapsed;
$pg .= '<td class=dr>'.dsprate($hr).'</td>'; $pg .= '<td class=dr>'.dsprate($hr).'</td>';
$shareacc = $ans['shareacc:'.$i]; $shareacc = $ans[$pre.'shareacc:'.$i];
$pg .= '<td class=dr>'.difffmt($shareacc).'</td>'; $pg .= '<td class=dr>'.difffmt($shareacc).'</td>';
if ($shareacc > 0) if ($shareacc > 0)
$avgsh = $diffacc / $shareacc; $avgsh = $diffacc / $shareacc;

3
pool/page_userset.php

@ -8,6 +8,9 @@ function uset($data, $user, $api, $err)
$pg .= "<span class=err>$err<br><br></span>"; $pg .= "<span class=err>$err<br><br></span>";
$pg .= '<table cellpadding=20 cellspacing=0 border=1>'; $pg .= '<table cellpadding=20 cellspacing=0 border=1>';
$pg .= '<tr class=dc><td><span class=nb>';
$pg .= "<input type=checkbox id=minicb onclick='md(this)'>";
$pg .= 'mini header</span></td></tr>';
$pg .= '<tr class=dc><td><center>'; $pg .= '<tr class=dc><td><center>';
$pg .= makeForm('userset'); $pg .= makeForm('userset');

78
pool/page_usperf.php

@ -1,24 +1,53 @@
<?php <?php
# #
function uspg() function uspg($nc)
{ {
$g = "function gdrw(c,d,cbx){gc(c);ghrs(c);gopt(c,cbx); $g = "function gdrw(c,d,cbx){gc(c);ghrs(c);gopt(c,cbx);
gfs(c,'white');gss(c,'#0000c0');glw(c,2);gbd(c); gfs(c,'white');gss(c,'#0000c0');glw(c,2);gbd(c);
var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0,tda=0; var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0,tda=[];
for(var i=0;i<rows;i++){var s=parseFloat(d['start:'+i]);var e=parseFloat(d['end:'+i]);var da=parseFloat(d['diffacc:'+i]);tda+=da;var ths=(da/(e-s))*Math.pow(2,32)/Math.pow(10,12);d['ths:'+i]=ths;if(ymin==-1||ymin>ths){ymin=ths}if(ths>ymax)ymax=ths;d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax<e){xmax=e}d['vx:'+i]=(s+e)/2.0}; var w=d['arp'].split(',');var cols=d['cols'].split(',');
var tav=(tda/(xmax-xmin))*Math.pow(2,32)/Math.pow(10,12); for(var j=1;j<w.length;j++){tda[j-1]=0}
for(var i=0;i<rows;i++){var s=parseFloat(d['start:'+i]);var e=parseFloat(d['end:'+i]);d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax<e){xmax=e}d['vx:'+i]=(s+e)/2.0;
for(var j=1;j<w.length;j++){var pre=w[j];var ths=0,nam=pre+'diffacc:'+i;if(d[nam]){var da=parseFloat(d[nam]);ths=(da/(e-s))*Math.pow(2,32)/Math.pow(10,12);tda[j-1]+=da}d[pre+'ths:'+i]=ths;if(ymin==-1||ymin>ths){ymin=ths}if(ths>ymax)ymax=ths;document.getElementById('worker'+j).value=d[pre+'worker']}
}
for(var j=1;j<w.length;j++){tda[j-1]*=(Math.pow(2,32)/Math.pow(10,12)/(xmax-xmin))}
var p5=(ymax-ymin)*0.05;ymax+=p5;ymin-=p5;if(ymin<0){ymin=0} var p5=(ymax-ymin)*0.05;ymax+=p5;ymin-=p5;if(ymin<0){ymin=0}
if(c['zerob']){ymin=0} if(c['zerob']){ymin=0}
ggr(c,0.9,0.9,'TH/s',rows,xmin,xmax,ymin,ymax,d,'nx:','vx:','ths:',tav)} ghg(c,xmax-xmin);
ggr(c,0.9,0.9,'TH/s',rows,xmin,xmax,ymin,ymax,d,'nx:','vx:','ths:',tda,w,cols)}
c={}; c={};
function dodrw(data,cbx){if(hasCan()){gdrw(c,sep(data),cbx)}} function dodrw(data,cbx){if(hasCan()){gdrw(c,sep(data),cbx)}}
function gact(t){if(t.checked){scnv(t.id,1)}else{scnv(t.id,0)}godrw(0)}"; function gact(t){if(t.checked){scnv(t.id,1)}else{scnv(t.id,0)}godrw(0)}
function wch(){var w='';for(var i=1;i<=$nc;i++){var e=document.getElementById('worker'+i);if(e&&e.value&&e.value.trim()){if(i>1){w+=','}w+=e.value.trim()}}if(w){scnv('workers',w)}}";
return $g; return $g;
} }
# #
function dousperf($data, $user) function dousperf($data, $user)
{ {
$ans = getShiftData($user); global $fld_sep, $val_sep;
// This also defines how many worker fields there are
$cols = array('#0000c0', '#00dd00', '#e06020', '#b020e0');
$nc = count($cols);
$workers = 'all';
if (isset($_COOKIE['workers']))
{
$w = substr(trim($_COOKIE['workers']), 0, 1024);
if ($w !== false)
{
$wa = explode(',', $w, $nc+1);
if (count($wa) > $nc)
{
$w = '';
for ($i = 0; $i < $nc; $i++)
$w .= (($i == 0) ? '' : ',').$wa[$i];
}
$workers = $w;
}
}
$ans = getShiftData($user, $workers);
$iCrap = strpos($_SERVER['HTTP_USER_AGENT'],'iP'); $iCrap = strpos($_SERVER['HTTP_USER_AGENT'],'iP');
if ($iCrap) if ($iCrap)
@ -27,9 +56,11 @@ function dousperf($data, $user)
$vlines = true; $vlines = true;
$pg = '<h1>User Shift Reward Performance</h1><br>'; $pg = '<h1>User Shift Reward Performance</h1><br>';
if ($ans['STATUS'] == 'ok' and $ans['DATA'] != '') if ($ans['STATUS'] == 'ok' and $ans['DATA'] != '')
{ {
addGBase(); addGBase();
addTips();
$cbx = array('skey' => 'shift key', 'slines' => 'shift lines', $cbx = array('skey' => 'shift key', 'slines' => 'shift lines',
'tkey' => 'time key', 'tlines' => 'time lines', 'tkey' => 'time key', 'tlines' => 'time lines',
'over' => 'key overlap', 'smooth' => 'smooth', 'over' => 'key overlap', 'smooth' => 'smooth',
@ -38,17 +69,44 @@ function dousperf($data, $user)
if ($vlines === true) if ($vlines === true)
$xon['slines'] = 1; $xon['slines'] = 1;
$pg .= '<div>'; $pg .= '<form>';
$tt = "<ul class=tip><li>all = all workers</li><li>noname = worker with no workername</li>";
$tt .= "<li>or full workername without the username i.e. .worker or _worker</li></ul>";
$pg .= "<span class=q onclick='tip(\"wtip\",6000)'>?</span>";
$pg .= "<span class=tip0><span class=notip id=wtip>$tt</span></span>";
$i = 0;
$datacols = '';
$onch = " onchange='wch()'";
foreach ($cols as $col)
{
$i++;
$pg .= " <span class=nb><font color=$col>Worker$i:</font>";
$pg .= "<input type=text size=10 id=worker$i$onch> </span>";
if ($i > 1)
$datacols .= ',';
$datacols .= $col;
}
$oncl = "wch();location.href=\"".makeURL('usperf')."\"";
$pg .= "<button type=button onclick='$oncl'>Update</button></form><div>";
foreach ($cbx as $nam => $txt) foreach ($cbx as $nam => $txt)
$pg .= "&nbsp;<input type=checkbox id=$nam onclick='gact(this)'>$txt&nbsp;"; {
$pg .= ' <span class=nb>';
$pg .= "<input type=checkbox id=$nam onclick='gact(this)'>";
$pg .= "$txt&nbsp;</span>";
}
$pg .= '</div>'; $pg .= '</div>';
$pg .= '<div id=can0><canvas id=can width=1 height=1>'; $pg .= '<div id=can0><canvas id=can width=1 height=1>';
$pg .= 'A graph will show here if your browser supports html5/canvas'; $pg .= 'A graph will show here if your browser supports html5/canvas';
$pg .= "</canvas></div>\n"; $pg .= "</canvas></div>\n";
$data = str_replace(array("\\","'"), array("\\\\","\\'"), $ans['DATA']); $data = str_replace(array("\\","'"), array("\\\\","\\'"), $ans['DATA']);
$data .= $fld_sep . 'cols' . $val_sep . $datacols;
$pg .= "<script type='text/javascript'>\n"; $pg .= "<script type='text/javascript'>\n";
$pg .= uspg(); $pg .= uspg($nc);
$pg .= "\nfunction godrw(f){var cbx=["; $pg .= "\nfunction godrw(f){var cbx=[";
$comma = ''; $comma = '';
foreach ($cbx as $nam => $txt) foreach ($cbx as $nam => $txt)

21
pool/page_workers.php

@ -22,7 +22,8 @@ function workhashorder($a, $b)
# #
function workuser($data, $user, &$offset, &$totshare, &$totdiff, function workuser($data, $user, &$offset, &$totshare, &$totdiff,
&$totinvalid, &$totrate, &$blockacc, &$totinvalid, &$totrate, &$blockacc,
&$blockreward, $old = false, $srt = false) &$blockreward, $old = false, $srt = false,
$one = false, &$title)
{ {
$ans = getWorkers($user); $ans = getWorkers($user);
@ -33,6 +34,13 @@ function workuser($data, $user, &$offset, &$totshare, &$totdiff,
$blockacc = $ans['blockacc']; $blockacc = $ans['blockacc'];
if (isset($ans['blockreward'])) if (isset($ans['blockreward']))
$blockreward = $ans['blockreward']; $blockreward = $ans['blockreward'];
if ($one === true && isset($ans['oldworkers']))
{
$days = intval($ans['oldworkers']);
if ($days != 0)
$title = '&nbsp;(active during the last '.$days.' day'.
(($days==1)?'':'s').')';
}
$all = array(); $all = array();
$count = $ans['rows']; $count = $ans['rows'];
for ($i = 0; $i < $count; $i++) for ($i = 0; $i < $count; $i++)
@ -151,9 +159,9 @@ function worktotal($offset, $totshare, $totdiff, $totinvalid, $totrate, $blockac
# #
function doworker($data, $user) function doworker($data, $user)
{ {
$pg = '<h1>Workers</h1>'; $title = '';
$pg .= "<table callpadding=0 cellspacing=0 border=0>\n"; $pg = "<table callpadding=0 cellspacing=0 border=0>\n";
$totshare = 0; $totshare = 0;
$totdiff = 0; $totdiff = 0;
@ -165,11 +173,12 @@ function doworker($data, $user)
$pg .= worktitle($data, $user); $pg .= worktitle($data, $user);
$pg .= workuser($data, $user, $offset, $totshare, $totdiff, $totinvalid, $pg .= workuser($data, $user, $offset, $totshare, $totdiff, $totinvalid,
$totrate, $blockacc, $blockreward, false, true); $totrate, $blockacc, $blockreward, false, true, true,
$title);
$pg .= worktotal($offset, $totshare, $totdiff, $totinvalid, $totrate, $pg .= worktotal($offset, $totshare, $totdiff, $totinvalid, $totrate,
$blockacc, $blockreward); $blockacc, $blockreward);
if ($blockacc > 0 && $blockreward > 0) if (false && $blockacc > 0 && $blockreward > 0)
{ {
$btc = btcfmt($totdiff / $blockacc * $blockreward); $btc = btcfmt($totdiff / $blockacc * $blockreward);
$pg .= '<tr><td colspan=8 class=dc>'; $pg .= '<tr><td colspan=8 class=dc>';
@ -179,7 +188,7 @@ function doworker($data, $user)
$pg .= "</table>\n"; $pg .= "</table>\n";
return $pg; return "<h1>Workers$title</h1>".$pg;
} }
# #
function doworkers($data, $user) function doworkers($data, $user)

33
pool/page_workmgt.php

@ -7,6 +7,21 @@ function workmgtuser($data, $user, $err)
if ($err != '') if ($err != '')
$pg .= "<span class=err>$err<br><br></span>"; $pg .= "<span class=err>$err<br><br></span>";
$ans = getWorkers($user, 'N');
if ($ans['STATUS'] == 'ok')
{
if (isset($ans['oldworkers']) && $ans['oldworkers'] == '0')
$chk = '';
else
$chk = ' checked';
$pg .= makeForm('workmgt');
$pg .= '<span>Active workers (7 days)';
$pg .= "<input type=checkbox name=seven$chk>";
$pg .= '<input type=submit name=S value=Update>';
$pg .= '</span></form><br><br>';
}
$pg .= makeForm('workmgt'); $pg .= makeForm('workmgt');
$pg .= "<table callpadding=0 cellspacing=0 border=0>\n"; $pg .= "<table callpadding=0 cellspacing=0 border=0>\n";
$pg .= '<tr class=title>'; $pg .= '<tr class=title>';
@ -14,8 +29,6 @@ function workmgtuser($data, $user, $err)
$pg .= '<td class=dr>Minimum Diff</td>'; $pg .= '<td class=dr>Minimum Diff</td>';
$pg .= '</tr>'; $pg .= '</tr>';
$ans = getWorkers($user, 'N');
$offset = 0; $offset = 0;
if ($ans['STATUS'] == 'ok') if ($ans['STATUS'] == 'ok')
{ {
@ -58,6 +71,21 @@ function workmgtuser($data, $user, $err)
function doworkmgt($data, $user) function doworkmgt($data, $user)
{ {
$err = ''; $err = '';
$S = getparam('S', false);
$chk = getparam('seven', false);
if ($S == 'Update')
{
$settings = array();
if ($chk == 'on')
$settings['oldworkers'] = '7';
else
$settings['oldworkers'] = '0';
$ans = workerSet($user, $settings);
if ($ans['STATUS'] != 'ok')
$err = $ans['ERROR'];
}
else
{
$OK = getparam('OK', false); $OK = getparam('OK', false);
$count = getparam('rows', false); $count = getparam('rows', false);
if ($OK == 'OK' && !nuem($count)) if ($OK == 'OK' && !nuem($count))
@ -80,6 +108,7 @@ function doworkmgt($data, $user)
$err = $ans['ERROR']; $err = $ans['ERROR'];
} }
} }
}
$pg = workmgtuser($data, $user, $err); $pg = workmgtuser($data, $user, $err);

5
pool/prime.php

@ -79,11 +79,12 @@ function check()
'Shifts' => 'shifts', 'Shifts' => 'shifts',
'Shift Graph' => 'usperf', 'Shift Graph' => 'usperf',
'Workers' => 'workers', 'Workers' => 'workers',
'Management' => 'workmgt', 'Management' => 'workmgt'
), ),
'Pool' => array( 'Pool' => array(
'Stats' => 'stats', 'Stats' => 'stats',
'Blocks' => 'blocks' 'Blocks' => 'blocks',
'Graph' => 'psperf'
), ),
'Admin' => NULL, 'Admin' => NULL,
'gap' => array( # options not shown 'gap' => array( # options not shown

145
src/ckdb.c

@ -153,8 +153,8 @@ static bool markersummary_auto;
int switch_state = SWITCH_STATE_ALL; int switch_state = SWITCH_STATE_ALL;
// disallow: '/' '.' '_' and FLDSEP // disallow: '/' WORKSEP1 WORKSEP2 and FLDSEP
const char *userpatt = "^[^/\\._"FLDSEPSTR"]*$"; const char *userpatt = "^[^/"WORKSEP1PATT WORKSEP2STR FLDSEPSTR"]*$";
const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.-]*[A-Za-z0-9]$"; const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.-]*[A-Za-z0-9]$";
const char *idpatt = "^[_A-Za-z][_A-Za-z0-9]*$"; const char *idpatt = "^[_A-Za-z][_A-Za-z0-9]*$";
const char *intpatt = "^[0-9][0-9]*$"; const char *intpatt = "^[0-9][0-9]*$";
@ -215,6 +215,9 @@ bool confirm_sharesummary;
/* Optional workinfoid range -Y to supply when confirming sharesummaries /* Optional workinfoid range -Y to supply when confirming sharesummaries
* N.B. if you specify -Y it will enable -y, so -y isn't also required * N.B. if you specify -Y it will enable -y, so -y isn't also required
* *
* TODO: update to include markersummaries
* -Y/-y isn't currently usable since it won't work without the update
*
* Default (NULL) is to confirm all aged sharesummaries * Default (NULL) is to confirm all aged sharesummaries
* Default should normally be used every time * Default should normally be used every time
* The below options are mainly for debugging or * The below options are mainly for debugging or
@ -379,17 +382,24 @@ double current_ndiff;
K_TREE *shares_root; K_TREE *shares_root;
K_LIST *shares_free; K_LIST *shares_free;
K_STORE *shares_store; K_STORE *shares_store;
K_TREE *shares_early_root;
K_STORE *shares_early_store;
// SHAREERRORS shareerrors.id.json={...} // SHAREERRORS shareerrors.id.json={...}
K_TREE *shareerrors_root; K_TREE *shareerrors_root;
K_LIST *shareerrors_free; K_LIST *shareerrors_free;
K_STORE *shareerrors_store; K_STORE *shareerrors_store;
K_TREE *shareerrors_early_root;
K_STORE *shareerrors_early_store;
// SHARESUMMARY // SHARESUMMARY
K_TREE *sharesummary_root; K_TREE *sharesummary_root;
K_TREE *sharesummary_workinfoid_root; K_TREE *sharesummary_workinfoid_root;
K_LIST *sharesummary_free; K_LIST *sharesummary_free;
K_STORE *sharesummary_store; K_STORE *sharesummary_store;
// Pool total sharesummary stats
K_TREE *sharesummary_pool_root;
K_STORE *sharesummary_pool_store;
// BLOCKS block.id.json={...} // BLOCKS block.id.json={...}
const char *blocks_new = "New"; const char *blocks_new = "New";
@ -450,6 +460,9 @@ K_TREE *markersummary_root;
K_TREE *markersummary_userid_root; K_TREE *markersummary_userid_root;
K_LIST *markersummary_free; K_LIST *markersummary_free;
K_STORE *markersummary_store; K_STORE *markersummary_store;
// Pool total markersummary stats
K_TREE *markersummary_pool_root;
K_STORE *markersummary_pool_store;
// WORKMARKERS // WORKMARKERS
K_TREE *workmarkers_root; K_TREE *workmarkers_root;
@ -995,12 +1008,16 @@ static void alloc_storage()
shares_free = k_new_list("Shares", sizeof(SHARES), shares_free = k_new_list("Shares", sizeof(SHARES),
ALLOC_SHARES, LIMIT_SHARES, true); ALLOC_SHARES, LIMIT_SHARES, true);
shares_store = k_new_store(shares_free); shares_store = k_new_store(shares_free);
shares_early_store = k_new_store(shares_free);
shares_root = new_ktree(); shares_root = new_ktree();
shares_early_root = new_ktree();
shareerrors_free = k_new_list("ShareErrors", sizeof(SHAREERRORS), shareerrors_free = k_new_list("ShareErrors", sizeof(SHAREERRORS),
ALLOC_SHAREERRORS, LIMIT_SHAREERRORS, true); ALLOC_SHAREERRORS, LIMIT_SHAREERRORS, true);
shareerrors_store = k_new_store(shareerrors_free); shareerrors_store = k_new_store(shareerrors_free);
shareerrors_early_store = k_new_store(shareerrors_free);
shareerrors_root = new_ktree(); shareerrors_root = new_ktree();
shareerrors_early_root = new_ktree();
sharesummary_free = k_new_list("ShareSummary", sizeof(SHARESUMMARY), sharesummary_free = k_new_list("ShareSummary", sizeof(SHARESUMMARY),
ALLOC_SHARESUMMARY, LIMIT_SHARESUMMARY, true); ALLOC_SHARESUMMARY, LIMIT_SHARESUMMARY, true);
@ -1008,6 +1025,8 @@ static void alloc_storage()
sharesummary_root = new_ktree(); sharesummary_root = new_ktree();
sharesummary_workinfoid_root = new_ktree(); sharesummary_workinfoid_root = new_ktree();
sharesummary_free->dsp_func = dsp_sharesummary; sharesummary_free->dsp_func = dsp_sharesummary;
sharesummary_pool_store = k_new_store(sharesummary_free);
sharesummary_pool_root = new_ktree();
blocks_free = k_new_list("Blocks", sizeof(BLOCKS), blocks_free = k_new_list("Blocks", sizeof(BLOCKS),
ALLOC_BLOCKS, LIMIT_BLOCKS, true); ALLOC_BLOCKS, LIMIT_BLOCKS, true);
@ -1054,6 +1073,8 @@ static void alloc_storage()
markersummary_root = new_ktree(); markersummary_root = new_ktree();
markersummary_userid_root = new_ktree(); markersummary_userid_root = new_ktree();
markersummary_free->dsp_func = dsp_markersummary; markersummary_free->dsp_func = dsp_markersummary;
markersummary_pool_store = k_new_store(markersummary_free);
markersummary_pool_root = new_ktree();
workmarkers_free = k_new_list("WorkMarkers", sizeof(WORKMARKERS), workmarkers_free = k_new_list("WorkMarkers", sizeof(WORKMARKERS),
ALLOC_WORKMARKERS, LIMIT_WORKMARKERS, true); ALLOC_WORKMARKERS, LIMIT_WORKMARKERS, true);
@ -1106,6 +1127,11 @@ static void alloc_storage()
static void dealloc_storage() static void dealloc_storage()
{ {
SHAREERRORS *shareerrors;
SHARES *shares;
K_ITEM *s_item;
char *st = NULL;
LOGWARNING("%s() logqueue ...", __func__); LOGWARNING("%s() logqueue ...", __func__);
FREE_LISTS(logqueue); FREE_LISTS(logqueue);
@ -1121,6 +1147,9 @@ static void dealloc_storage()
LOGWARNING("%s() markersummary ...", __func__); LOGWARNING("%s() markersummary ...", __func__);
FREE_TREE(markersummary_pool);
k_list_transfer_to_tail(markersummary_pool_store, markersummary_store);
FREE_STORE(markersummary_pool);
FREE_TREE(markersummary_userid); FREE_TREE(markersummary_userid);
FREE_TREE(markersummary); FREE_TREE(markersummary);
FREE_STORE_DATA(markersummary); FREE_STORE_DATA(markersummary);
@ -1146,12 +1175,55 @@ static void dealloc_storage()
LOGWARNING("%s() sharesummary ...", __func__); LOGWARNING("%s() sharesummary ...", __func__);
FREE_TREE(sharesummary_pool);
k_list_transfer_to_tail(sharesummary_pool_store, sharesummary_store);
FREE_STORE(sharesummary_pool);
FREE_TREE(sharesummary_workinfoid); FREE_TREE(sharesummary_workinfoid);
FREE_TREE(sharesummary); FREE_TREE(sharesummary);
FREE_STORE_DATA(sharesummary); FREE_STORE_DATA(sharesummary);
FREE_LIST_DATA(sharesummary); FREE_LIST_DATA(sharesummary);
if (shareerrors_early_store->count > 0) {
LOGERR("%s() *** shareerrors_early count %d ***",
__func__, shareerrors_early_store->count);
s_item = shareerrors_early_store->head;
while (s_item) {
DATA_SHAREERRORS(shareerrors, s_item);
LOGERR("%s(): %"PRId64"/%s/%"PRId32"/%s/%ld,%ld",
__func__,
shareerrors->workinfoid,
st = safe_text(shareerrors->workername),
shareerrors->errn,
shareerrors->error,
shareerrors->createdate.tv_sec,
shareerrors->createdate.tv_usec);
FREENULL(st);
s_item = s_item->next;
}
}
FREE_TREE(shareerrors_early);
FREE_STORE(shareerrors_early);
FREE_ALL(shareerrors); FREE_ALL(shareerrors);
if (shares_early_store->count > 0) {
LOGERR("%s() *** shares_early count %d ***",
__func__, shares_early_store->count);
s_item = shares_early_store->head;
while (s_item) {
DATA_SHARES(shares, s_item);
LOGERR("%s(): %"PRId64"/%s/%s/%"PRId32"/%ld,%ld",
__func__,
shares->workinfoid,
st = safe_text(shares->workername),
shares->nonce,
shares->errn,
shares->createdate.tv_sec,
shares->createdate.tv_usec);
FREENULL(st);
s_item = s_item->next;
}
}
FREE_TREE(shares_early);
FREE_STORE(shares_early);
FREE_ALL(shares); FREE_ALL(shares);
LOGWARNING("%s() workinfo ...", __func__); LOGWARNING("%s() workinfo ...", __func__);
@ -1192,6 +1264,8 @@ static bool setup_data()
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
K_ITEM look, *found; K_ITEM look, *found;
WORKINFO wi, *wic, *wif; WORKINFO wi, *wic, *wif;
tv_t db_stt, db_fin, rel_stt, rel_fin;
double min, sec;
cklock_init(&fpm_lock); cklock_init(&fpm_lock);
cksem_init(&socketer_sem); cksem_init(&socketer_sem);
@ -1200,6 +1274,8 @@ static bool setup_data()
alloc_storage(); alloc_storage();
setnow(&db_stt);
if (!getdata1() || everyone_die) if (!getdata1() || everyone_die)
return false; return false;
@ -1219,11 +1295,25 @@ static bool setup_data()
if (!getdata3() || everyone_die) if (!getdata3() || everyone_die)
return false; return false;
setnow(&db_fin);
sec = tvdiff(&db_fin, &db_stt);
min = floor(sec / 60.0);
sec -= min * 60.0;
LOGWARNING("dbload complete %.0fm %.3fs", min, sec);
db_load_complete = true; db_load_complete = true;
setnow(&rel_stt);
if (!reload() || everyone_die) if (!reload() || everyone_die)
return false; return false;
setnow(&rel_fin);
sec = tvdiff(&rel_fin, &rel_stt);
min = floor(sec / 60.0);
sec -= min * 60.0;
LOGWARNING("reload complete %.0fm %.3fs", min, sec);
set_block_share_counters(); set_block_share_counters();
if (everyone_die) if (everyone_die)
@ -2582,8 +2672,8 @@ static void *socketer(__maybe_unused void *arg)
snprintf(reply, sizeof(reply), "%s.%ld.?.", id, now.tv_sec); snprintf(reply, sizeof(reply), "%s.%ld.?.", id, now.tv_sec);
send_unix_msg(sockd, reply); send_unix_msg(sockd, reply);
break; break;
case CMD_SHUTDOWN: case CMD_TERMINATE:
LOGWARNING("Listener received shutdown message, terminating ckdb"); LOGWARNING("Listener received terminate message, terminating ckdb");
snprintf(reply, sizeof(reply), "%s.%ld.ok.exiting", id, now.tv_sec); snprintf(reply, sizeof(reply), "%s.%ld.ok.exiting", id, now.tv_sec);
send_unix_msg(sockd, reply); send_unix_msg(sockd, reply);
everyone_die = true; everyone_die = true;
@ -2728,6 +2818,7 @@ static void *socketer(__maybe_unused void *arg)
case CMD_PAYOUTS: case CMD_PAYOUTS:
case CMD_MPAYOUTS: case CMD_MPAYOUTS:
case CMD_SHIFTS: case CMD_SHIFTS:
case CMD_PSHIFT:
case CMD_DSP: case CMD_DSP:
case CMD_BLOCKSTATUS: case CMD_BLOCKSTATUS:
if (!startup_complete) { if (!startup_complete) {
@ -2919,7 +3010,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
case CMD_REPLY: case CMD_REPLY:
break; break;
// Shouldn't be there // Shouldn't be there
case CMD_SHUTDOWN: case CMD_TERMINATE:
case CMD_PING: case CMD_PING:
case CMD_VERSION: case CMD_VERSION:
case CMD_LOGLEVEL: case CMD_LOGLEVEL:
@ -2951,6 +3042,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
case CMD_SHIFTS: case CMD_SHIFTS:
case CMD_USERSTATUS: case CMD_USERSTATUS:
case CMD_MARKS: case CMD_MARKS:
case CMD_PSHIFT:
LOGERR("%s() Message line %"PRIu64" '%s' - invalid - ignored", LOGERR("%s() Message line %"PRIu64" '%s' - invalid - ignored",
__func__, count, cmd); __func__, count, cmd);
break; break;
@ -2969,8 +3061,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
(char *)__func__, (char *)__func__,
inet_default, inet_default,
&cd, trf_root); &cd, trf_root);
if (ans) FREENULL(ans);
free(ans);
break; break;
default: default:
// Force this switch to be updated if new cmds are added // Force this switch to be updated if new cmds are added
@ -3128,7 +3219,7 @@ static bool reload_from(tv_t *start)
LOGWARNING("%s(): %sread %"PRIu64" line%s from %s", LOGWARNING("%s(): %sread %"PRIu64" line%s from %s",
__func__, __func__,
everyone_die ? "Shutdown, aborting - " : "", everyone_die ? "Terminate, aborting - " : "",
count, count == 1 ? "" : "s", count, count == 1 ? "" : "s",
filename); filename);
total += count; total += count;
@ -3239,7 +3330,7 @@ static void process_queued(PGconn *conn, K_ITEM *wq_item)
&(workqueue->now), workqueue->by, &(workqueue->now), workqueue->by,
workqueue->code, workqueue->inet, workqueue->code, workqueue->inet,
&(workqueue->cd), workqueue->trf_root); &(workqueue->cd), workqueue->trf_root);
free(ans); FREENULL(ans);
} }
if (last_buf) if (last_buf)
@ -3278,6 +3369,10 @@ static void *listener(void *arg)
K_ITEM *wq_item; K_ITEM *wq_item;
time_t now; time_t now;
int wqcount, wqgot; int wqcount, wqgot;
char ooo_buf[256];
tv_t wq_stt, wq_fin;
double min, sec;
int left;
logqueue_free = k_new_list("LogQueue", sizeof(LOGQUEUE), logqueue_free = k_new_list("LogQueue", sizeof(LOGQUEUE),
ALLOC_LOGQUEUE, LIMIT_LOGQUEUE, true); ALLOC_LOGQUEUE, LIMIT_LOGQUEUE, true);
@ -3308,6 +3403,8 @@ static void *listener(void *arg)
wqcount = workqueue_store->count; wqcount = workqueue_store->count;
K_RUNLOCK(workqueue_store); K_RUNLOCK(workqueue_store);
LOGWARNING("reload shares OoO %s", ooo_status(ooo_buf, sizeof(ooo_buf)));
LOGWARNING("%s(): ckdb ready, queue %d", __func__, wqcount); LOGWARNING("%s(): ckdb ready, queue %d", __func__, wqcount);
/* Until startup_complete, the values should be ignored /* Until startup_complete, the values should be ignored
@ -3322,17 +3419,23 @@ static void *listener(void *arg)
ck_wunlock(&last_lock); ck_wunlock(&last_lock);
startup_complete = true; startup_complete = true;
}
// Process queued work setnow(&wq_stt);
conn = dbconnect(); conn = dbconnect();
now = time(NULL); now = time(NULL);
wqgot = 0; wqgot = 0;
}
// Process queued work
while (!everyone_die) { while (!everyone_die) {
K_WLOCK(workqueue_store); K_WLOCK(workqueue_store);
wq_item = k_unlink_head(workqueue_store); wq_item = k_unlink_head(workqueue_store);
left = workqueue_store->count;
K_WUNLOCK(workqueue_store); K_WUNLOCK(workqueue_store);
if (left == 0 && wq_stt.tv_sec != 0L)
setnow(&wq_fin);
/* Don't keep a connection for more than ~10s or ~10000 items /* Don't keep a connection for more than ~10s or ~10000 items
* but always have a connection open */ * but always have a connection open */
if ((time(NULL) - now) > 10 || wqgot > 10000) { if ((time(NULL) - now) > 10 || wqgot > 10000) {
@ -3346,7 +3449,19 @@ static void *listener(void *arg)
wqgot++; wqgot++;
process_queued(conn, wq_item); process_queued(conn, wq_item);
tick(); tick();
} else { }
if (left == 0 && wq_stt.tv_sec != 0L) {
sec = tvdiff(&wq_fin, &wq_stt);
min = floor(sec / 60.0);
sec -= min * 60.0;
LOGWARNING("reload queue completed %.0fm %.3fs", min, sec);
// Used as the flag to display the message once
wq_stt.tv_sec = 0L;
}
if (!wq_item) {
const ts_t tsdiff = {0, 420000000}; const ts_t tsdiff = {0, 420000000};
tv_t now; tv_t now;
ts_t abs; ts_t abs;
@ -4190,7 +4305,7 @@ int main(int argc, char **argv)
sigaction(SIGTERM, &handler, NULL); sigaction(SIGTERM, &handler, NULL);
sigaction(SIGINT, &handler, NULL); sigaction(SIGINT, &handler, NULL);
/* Shutdown from here if the listener is sent a shutdown message */ /* Terminate from here if the listener is sent a terminate message */
join_pthread(ckp.pth_listener); join_pthread(ckp.pth_listener);
} }
@ -4205,9 +4320,9 @@ int main(int argc, char **argv)
curr = time(NULL); curr = time(NULL);
if (curr - start > 4) { if (curr - start > 4) {
if (curr - trigger > 4) { if (curr - trigger > 4) {
msg = "Shutdown initial delay"; msg = "Terminate initial delay";
} else if (curr - trigger > 2) { } else if (curr - trigger > 2) {
msg = "Shutdown delay"; msg = "Terminate delay";
} }
} }
if (msg) { if (msg) {

106
src/ckdb.h

@ -55,7 +55,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "1.0.0" #define DB_VERSION "1.0.0"
#define CKDB_VERSION DB_VERSION"-1.035" #define CKDB_VERSION DB_VERSION"-1.066"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -176,6 +176,12 @@ extern POOLSTATUS pool;
#define FLDSEP 0x09 #define FLDSEP 0x09
#define FLDSEPSTR "\011" #define FLDSEPSTR "\011"
#define WORKSEP1 '.'
#define WORKSEP1STR "."
#define WORKSEP1PATT "\\."
#define WORKSEP2 '_'
#define WORKSEP2STR "_"
#define MAXID 0x7fffffffffffffffLL #define MAXID 0x7fffffffffffffffLL
/* N.B. STRNCPY() truncates, whereas txt_to_str() aborts ckdb if src > trg /* N.B. STRNCPY() truncates, whereas txt_to_str() aborts ckdb if src > trg
@ -226,6 +232,7 @@ enum data_type {
TYPE_BIGINT, TYPE_BIGINT,
TYPE_INT, TYPE_INT,
TYPE_TV, TYPE_TV,
TYPE_BTV,
TYPE_TVS, TYPE_TVS,
TYPE_CTV, TYPE_CTV,
TYPE_FTV, TYPE_FTV,
@ -336,7 +343,7 @@ extern char *id_default;
enum cmd_values { enum cmd_values {
CMD_UNSET, CMD_UNSET,
CMD_REPLY, // Means something was wrong - send back reply CMD_REPLY, // Means something was wrong - send back reply
CMD_SHUTDOWN, CMD_TERMINATE,
CMD_PING, CMD_PING,
CMD_VERSION, CMD_VERSION,
CMD_LOGLEVEL, CMD_LOGLEVEL,
@ -375,6 +382,7 @@ enum cmd_values {
CMD_SHIFTS, CMD_SHIFTS,
CMD_USERSTATUS, CMD_USERSTATUS,
CMD_MARKS, CMD_MARKS,
CMD_PSHIFT,
CMD_END CMD_END
}; };
@ -721,7 +729,7 @@ typedef struct transfer {
// Suggest malloc use MMAP - 1913 = largest under 2MB // Suggest malloc use MMAP - 1913 = largest under 2MB
#define ALLOC_TRANSFER 1913 #define ALLOC_TRANSFER 1913
#define LIMIT_TRANSFER 0 #define LIMIT_TRANSFER 0
#define CULL_TRANSFER 16 #define CULL_TRANSFER 64
#define INIT_TRANSFER(_item) INIT_GENERIC(_item, transfer) #define INIT_TRANSFER(_item) INIT_GENERIC(_item, transfer)
#define DATA_TRANSFER(_var, _item) DATA_GENERIC(_var, _item, transfer, true) #define DATA_TRANSFER(_var, _item) DATA_GENERIC(_var, _item, transfer, true)
@ -747,7 +755,7 @@ extern tv_t missing_secuser_max;
typedef struct users { typedef struct users {
int64_t userid; int64_t userid;
char username[TXT_BIG+1]; char username[TXT_BIG+1];
char usertrim[TXT_BIG+1]; // Non DB field char usertrim[TXT_BIG+1]; // non-DB field
// Anything in 'status' fails mining authentication // Anything in 'status' fails mining authentication
char status[TXT_BIG+1]; char status[TXT_BIG+1];
char emailaddress[TXT_BIG+1]; char emailaddress[TXT_BIG+1];
@ -800,6 +808,8 @@ extern K_STORE *useratts_store;
// This att means the user uses multiple % based payout addresses // This att means the user uses multiple % based payout addresses
#define USER_MULTI_PAYOUT "PayAddresses" #define USER_MULTI_PAYOUT "PayAddresses"
#define USER_OLD_WORKERS "OldWorkersDays"
#define USER_OLD_WORKERS_DEFAULT 7
// WORKERS // WORKERS
typedef struct workers { typedef struct workers {
@ -836,6 +846,16 @@ extern K_STORE *workers_store;
#define IDLENOTIFICATIONTIME_DEF 0 #define IDLENOTIFICATIONTIME_DEF 0
#define IDLENOTIFICATIONTIME_DEF_STR STRINT(IDLENOTIFICATIONTIME_DEF) #define IDLENOTIFICATIONTIME_DEF_STR STRINT(IDLENOTIFICATIONTIME_DEF)
#define WORKERS_SEL_SEP ','
#define WORKERS_SEL_SEP_STR ","
/* There are 2 special select workernames
* A DB workername can't accidentally match them
* when including the WORKSEPx at the front of the workername,
* since these 2 don't start with WORKSEP1 or WORKSEP2 */
#define WORKERS_ALL "all"
// Empty has a value rather than "", so that "" means nothing selected
#define WORKERS_EMPTY "noname"
// PAYMENTADDRESSES // PAYMENTADDRESSES
typedef struct paymentaddresses { typedef struct paymentaddresses {
int64_t paymentaddressid; int64_t paymentaddressid;
@ -843,7 +863,7 @@ typedef struct paymentaddresses {
char payaddress[TXT_BIG+1]; char payaddress[TXT_BIG+1];
int32_t payratio; int32_t payratio;
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
bool match; // Non-db field bool match; // non-DB field
} PAYMENTADDRESSES; } PAYMENTADDRESSES;
#define ALLOC_PAYMENTADDRESSES 1024 #define ALLOC_PAYMENTADDRESSES 1024
@ -873,7 +893,7 @@ typedef struct payments {
char committxn[TXT_BIG+1]; char committxn[TXT_BIG+1];
char commitblockhash[TXT_BIG+1]; char commitblockhash[TXT_BIG+1];
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
K_ITEM *old_item; // Non-db field K_ITEM *old_item; // non-DB field
} PAYMENTS; } PAYMENTS;
#define ALLOC_PAYMENTS 1024 #define ALLOC_PAYMENTS 1024
@ -1024,6 +1044,8 @@ typedef struct shares {
char error[TXT_SML+1]; char error[TXT_SML+1];
char secondaryuserid[TXT_SML+1]; char secondaryuserid[TXT_SML+1];
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
int32_t redo; // non-DB field
int32_t oldcount; // non-DB field
} SHARES; } SHARES;
#define ALLOC_SHARES 10000 #define ALLOC_SHARES 10000
@ -1034,6 +1056,13 @@ typedef struct shares {
extern K_TREE *shares_root; extern K_TREE *shares_root;
extern K_LIST *shares_free; extern K_LIST *shares_free;
extern K_STORE *shares_store; extern K_STORE *shares_store;
// shares unexpectedly before the workinfo
extern K_TREE *shares_early_root;
extern K_STORE *shares_early_store;
/* Once a share is this old, it can only once more be
check for it's workinfoid and then be discarded */
#define EARLYSHARESLIMIT 60.0
// SHAREERRORS shareerrors.id.json={...} // SHAREERRORS shareerrors.id.json={...}
typedef struct shareerrors { typedef struct shareerrors {
@ -1045,9 +1074,11 @@ typedef struct shareerrors {
char error[TXT_SML+1]; char error[TXT_SML+1];
char secondaryuserid[TXT_SML+1]; char secondaryuserid[TXT_SML+1];
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
int32_t redo; // non-DB field
int32_t oldcount; // non-DB field
} SHAREERRORS; } SHAREERRORS;
#define ALLOC_SHAREERRORS 10000 #define ALLOC_SHAREERRORS 1000
#define LIMIT_SHAREERRORS 0 #define LIMIT_SHAREERRORS 0
#define INIT_SHAREERRORS(_item) INIT_GENERIC(_item, shareerrors) #define INIT_SHAREERRORS(_item) INIT_GENERIC(_item, shareerrors)
#define DATA_SHAREERRORS(_var, _item) DATA_GENERIC(_var, _item, shareerrors, true) #define DATA_SHAREERRORS(_var, _item) DATA_GENERIC(_var, _item, shareerrors, true)
@ -1055,6 +1086,9 @@ typedef struct shareerrors {
extern K_TREE *shareerrors_root; extern K_TREE *shareerrors_root;
extern K_LIST *shareerrors_free; extern K_LIST *shareerrors_free;
extern K_STORE *shareerrors_store; extern K_STORE *shareerrors_store;
// shareerrors unexpectedly before the workinfo
extern K_TREE *shareerrors_early_root;
extern K_STORE *shareerrors_early_store;
// SHARESUMMARY // SHARESUMMARY
typedef struct sharesummary { typedef struct sharesummary {
@ -1102,6 +1136,9 @@ extern K_TREE *sharesummary_root;
extern K_TREE *sharesummary_workinfoid_root; extern K_TREE *sharesummary_workinfoid_root;
extern K_LIST *sharesummary_free; extern K_LIST *sharesummary_free;
extern K_STORE *sharesummary_store; extern K_STORE *sharesummary_store;
// Pool total sharesummary stats
extern K_TREE *sharesummary_pool_root;
extern K_STORE *sharesummary_pool_store;
// BLOCKS block.id.json={...} // BLOCKS block.id.json={...}
typedef struct blocks { typedef struct blocks {
@ -1123,12 +1160,12 @@ typedef struct blocks {
int64_t elapsed; int64_t elapsed;
char statsconfirmed[TXT_FLAG+1]; char statsconfirmed[TXT_FLAG+1];
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
bool ignore; // Non DB field bool ignore; // non-DB field
// Calculated only when = 0 // Calculated only when = 0
double netdiff; double netdiff;
/* Non DB fields for the web page /* non-DB fields for the web page
* Calculate them once off/recalc them when required */ * Calculate them once off/recalc them when required */
double blockdiffratio; double blockdiffratio;
double blockcdf; double blockcdf;
@ -1193,7 +1230,7 @@ typedef struct miningpayouts {
double diffacc; double diffacc;
int64_t amount; int64_t amount;
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
K_ITEM *old_item; // Non-db field K_ITEM *old_item; // non-DB field
} MININGPAYOUTS; } MININGPAYOUTS;
#define ALLOC_MININGPAYOUTS 1000 #define ALLOC_MININGPAYOUTS 1000
@ -1249,6 +1286,12 @@ extern cklock_t process_pplns_lock;
#define PAYOUTS_ORPHAN_STR "O" #define PAYOUTS_ORPHAN_STR "O"
#define PAYORPHAN(_status) ((_status)[0] == PAYOUTS_ORPHAN) #define PAYORPHAN(_status) ((_status)[0] == PAYOUTS_ORPHAN)
// Default number of shifts (payouts) to display on web
#define SHIFTS_DEFAULT 99
/* OptionControl can override it
* UserAtts can also at the user level */
#define SHIFTS_SETTING_NAME "ShiftsPageSize"
/* /*
// EVENTLOG // EVENTLOG
typedef struct eventlog { typedef struct eventlog {
@ -1305,11 +1348,11 @@ typedef struct poolstats {
double hashrate5m; double hashrate5m;
double hashrate1hr; double hashrate1hr;
double hashrate24hr; double hashrate24hr;
bool stored; // Non-db field bool stored; // non-DB field
SIMPLEDATECONTROLFIELDS; SIMPLEDATECONTROLFIELDS;
} POOLSTATS; } POOLSTATS;
#define ALLOC_POOLSTATS 10000 #define ALLOC_POOLSTATS 1000
#define LIMIT_POOLSTATS 0 #define LIMIT_POOLSTATS 0
#define INIT_POOLSTATS(_item) INIT_GENERIC(_item, poolstats) #define INIT_POOLSTATS(_item) INIT_GENERIC(_item, poolstats)
#define DATA_POOLSTATS(_var, _item) DATA_GENERIC(_var, _item, poolstats, true) #define DATA_POOLSTATS(_var, _item) DATA_GENERIC(_var, _item, poolstats, true)
@ -1336,7 +1379,7 @@ typedef struct userstats {
double hashrate5m; double hashrate5m;
double hashrate1hr; double hashrate1hr;
double hashrate24hr; double hashrate24hr;
bool idle; // Non-db field bool idle; // non-DB field
char summarylevel[TXT_FLAG+1]; // SUMMARY_NONE in RAM char summarylevel[TXT_FLAG+1]; // SUMMARY_NONE in RAM
int32_t summarycount; int32_t summarycount;
tv_t statsdate; tv_t statsdate;
@ -1348,7 +1391,7 @@ typedef struct userstats {
* createdate batch, and thus could move all (complete) records * createdate batch, and thus could move all (complete) records
* matching the createdate from userstats_eos_store into the tree */ * matching the createdate from userstats_eos_store into the tree */
#define ALLOC_USERSTATS 10000 #define ALLOC_USERSTATS 1000
#define LIMIT_USERSTATS 0 #define LIMIT_USERSTATS 0
#define INIT_USERSTATS(_item) INIT_GENERIC(_item, userstats) #define INIT_USERSTATS(_item) INIT_GENERIC(_item, userstats)
#define DATA_USERSTATS(_var, _item) DATA_GENERIC(_var, _item, userstats, true) #define DATA_USERSTATS(_var, _item) DATA_GENERIC(_var, _item, userstats, true)
@ -1498,6 +1541,9 @@ extern K_TREE *markersummary_root;
extern K_TREE *markersummary_userid_root; extern K_TREE *markersummary_userid_root;
extern K_LIST *markersummary_free; extern K_LIST *markersummary_free;
extern K_STORE *markersummary_store; extern K_STORE *markersummary_store;
// Pool total markersummary stats
extern K_TREE *markersummary_pool_root;
extern K_STORE *markersummary_pool_store;
// WORKMARKERS // WORKMARKERS
typedef struct workmarkers { typedef struct workmarkers {
@ -1689,6 +1735,7 @@ extern char *_data_to_buf(enum data_type typ, void *data, char *buf, size_t siz,
#define ctv_to_buf(_data, _buf, _siz) _ctv_to_buf(_data, _buf, _siz, WHERE_FFL_HERE) #define ctv_to_buf(_data, _buf, _siz) _ctv_to_buf(_data, _buf, _siz, WHERE_FFL_HERE)
#define ftv_to_buf(_data, _buf, _siz) _ftv_to_buf(_data, _buf, _siz, WHERE_FFL_HERE) #define ftv_to_buf(_data, _buf, _siz) _ftv_to_buf(_data, _buf, _siz, WHERE_FFL_HERE)
#define tvs_to_buf(_data, _buf, _siz) _tvs_to_buf(_data, _buf, _siz, WHERE_FFL_HERE) #define tvs_to_buf(_data, _buf, _siz) _tvs_to_buf(_data, _buf, _siz, WHERE_FFL_HERE)
#define btv_to_buf(_data, _buf, _siz) _btv_to_buf(_data, _buf, _siz, WHERE_FFL_HERE)
//#define blob_to_buf(_data, _buf, _siz) _blob_to_buf(_data, _buf, _siz, WHERE_FFL_HERE) //#define blob_to_buf(_data, _buf, _siz) _blob_to_buf(_data, _buf, _siz, WHERE_FFL_HERE)
#define double_to_buf(_data, _buf, _siz) _double_to_buf(_data, _buf, _siz, WHERE_FFL_HERE) #define double_to_buf(_data, _buf, _siz) _double_to_buf(_data, _buf, _siz, WHERE_FFL_HERE)
@ -1702,6 +1749,8 @@ extern char *_ctv_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS);
extern char *_ftv_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS); extern char *_ftv_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS);
// Convert tv to seconds (ignore uS) // Convert tv to seconds (ignore uS)
extern char *_tvs_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS); extern char *_tvs_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS);
// Convert tv to (brief) DD HH:MM:SS
extern char *_btv_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS);
/* unused yet /* unused yet
extern char *_blob_to_buf(char *data, char *buf, size_t siz, WHERE_FFL_ARGS); extern char *_blob_to_buf(char *data, char *buf, size_t siz, WHERE_FFL_ARGS);
*/ */
@ -1770,6 +1819,8 @@ extern cmp_t cmp_accountbalance(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_accountbalance(int64_t userid); extern K_ITEM *find_accountbalance(int64_t userid);
extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height); extern K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height);
extern int64_t user_sys_setting(int64_t userid, char *setting_name,
int64_t setting_default, tv_t *now);
extern cmp_t cmp_workinfo(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_workinfo(K_ITEM *a, K_ITEM *b);
#define coinbase1height(_cb1) _coinbase1height(_cb1, WHERE_FFL_HERE) #define coinbase1height(_cb1) _coinbase1height(_cb1, WHERE_FFL_HERE)
extern int32_t _coinbase1height(char *coinbase1, WHERE_FFL_ARGS); extern int32_t _coinbase1height(char *coinbase1, WHERE_FFL_ARGS);
@ -1788,8 +1839,17 @@ extern void dsp_sharesummary(K_ITEM *item, FILE *stream);
extern cmp_t cmp_sharesummary(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_sharesummary(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_sharesummary_workinfoid(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_sharesummary_workinfoid(K_ITEM *a, K_ITEM *b);
extern void zero_sharesummary(SHARESUMMARY *row, tv_t *cd, double diff); extern void zero_sharesummary(SHARESUMMARY *row, tv_t *cd, double diff);
extern K_ITEM *find_sharesummary(int64_t userid, char *workername, #define find_sharesummary(_userid, _workername, _workinfoid) \
int64_t workinfoid); _find_sharesummary(_userid, _workername, _workinfoid, false)
#define find_sharesummary_p(_workinfoid) \
_find_sharesummary(KANO, EMPTY, _workinfoid, true)
#define POOL_SS(_row) do { \
(_row)->userid = KANO; \
(_row)->workername = strdup(EMPTY); \
} while (0)
extern K_ITEM *_find_sharesummary(int64_t userid, char *workername,
int64_t workinfoid, bool pool);
extern K_ITEM *find_last_sharesummary(int64_t userid, char *workername);
extern void auto_age_older(PGconn *conn, int64_t workinfoid, char *poolinstance, extern void auto_age_older(PGconn *conn, int64_t workinfoid, char *poolinstance,
char *by, char *code, char *inet, tv_t *cd); char *by, char *code, char *inet, tv_t *cd);
#define dbhash2btchash(_hash, _buf, _siz) \ #define dbhash2btchash(_hash, _buf, _siz) \
@ -1819,6 +1879,7 @@ extern cmp_t cmp_payouts_id(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_payouts(int32_t height, char *blockhash); extern K_ITEM *find_payouts(int32_t height, char *blockhash);
extern K_ITEM *find_last_payouts(); extern K_ITEM *find_last_payouts();
extern K_ITEM *find_payoutid(int64_t payoutid); extern K_ITEM *find_payoutid(int64_t payoutid);
extern double payout_stats(PAYOUTS *payouts, char *statname);
extern bool process_pplns(int32_t height, char *blockhash, tv_t *now); extern bool process_pplns(int32_t height, char *blockhash, tv_t *now);
extern cmp_t cmp_auths(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_auths(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_poolstats(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_poolstats(K_ITEM *a, K_ITEM *b);
@ -1830,8 +1891,16 @@ extern cmp_t cmp_markersummary(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_markersummary_userid(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_markersummary_userid(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_markersummary_userid(int64_t userid, char *workername, extern K_ITEM *find_markersummary_userid(int64_t userid, char *workername,
K_TREE_CTX *ctx); K_TREE_CTX *ctx);
extern K_ITEM *find_markersummary(int64_t workinfoid, int64_t userid, #define find_markersummary(_workinfoid, _userid, _workername) \
char *workername); _find_markersummary(0, _workinfoid, _userid, _workername, false)
#define find_markersummary_p(_markerid) \
_find_markersummary(_markerid, 0, KANO, EMPTY, true)
#define POOL_MS(_row) do { \
(_row)->userid = KANO; \
(_row)->workername = strdup(EMPTY); \
} while (0)
extern K_ITEM *_find_markersummary(int64_t markerid, int64_t workinfoid,
int64_t userid, char *workername, bool pool);
extern bool make_markersummaries(bool msg, char *by, char *code, char *inet, extern bool make_markersummaries(bool msg, char *by, char *code, char *inet,
tv_t *cd, K_TREE *trf_root); tv_t *cd, K_TREE *trf_root);
extern void dsp_workmarkers(K_ITEM *item, FILE *stream); extern void dsp_workmarkers(K_ITEM *item, FILE *stream);
@ -1965,6 +2034,7 @@ extern bool shareerrors_add(PGconn *conn, char *workinfoid, char *username,
extern bool sharesummaries_to_markersummaries(PGconn *conn, WORKMARKERS *workmarkers, extern bool sharesummaries_to_markersummaries(PGconn *conn, WORKMARKERS *workmarkers,
char *by, char *code, char *inet, char *by, char *code, char *inet,
tv_t *cd, K_TREE *trf_root); tv_t *cd, K_TREE *trf_root);
extern char *ooo_status(char *buf, size_t siz);
#define sharesummary_update(_conn, _s_row, _e_row, _ss_item, _by, _code, _inet, _cd) \ #define sharesummary_update(_conn, _s_row, _e_row, _ss_item, _by, _code, _inet, _cd) \
_sharesummary_update(_conn, _s_row, _e_row, _ss_item, _by, _code, _inet, _cd, \ _sharesummary_update(_conn, _s_row, _e_row, _ss_item, _by, _code, _inet, _cd, \
WHERE_FFL_HERE) WHERE_FFL_HERE)

564
src/ckdb_cmd.c

@ -9,6 +9,29 @@
#include "ckdb.h" #include "ckdb.h"
/*
* Allow overriding the username however the username must still be present
* This should ONLY be used for web reporting cmds i.e. read only
* Current PHP allows this for a hard coded user
*/
static K_ITEM *adminuser(K_TREE *trf_root, char *reply, size_t siz)
{
K_ITEM *i_username, *i_admin;
char reply2[1024] = "";
i_username = require_name(trf_root, "username", 3, (char *)userpatt,
reply, siz);
if (!i_username)
return NULL;
i_admin = optional_name(trf_root, "admin", 3, (char *)userpatt,
reply2, sizeof(reply2));
if (i_admin)
return i_admin;
return i_username;
}
static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
char *code, char *inet, __maybe_unused tv_t *notcd, char *code, char *inet, __maybe_unused tv_t *notcd,
K_TREE *trf_root) K_TREE *trf_root)
@ -408,16 +431,18 @@ struckout:
} }
static char *cmd_workerset(PGconn *conn, char *cmd, char *id, tv_t *now, static char *cmd_workerset(PGconn *conn, char *cmd, char *id, tv_t *now,
char *by, char *code, char *inet, char *by, char *code, char *inet, tv_t *cd,
__maybe_unused tv_t *notcd, K_TREE *trf_root) K_TREE *trf_root)
{ {
K_ITEM *i_username, *i_workername, *i_diffdef, *u_item, *w_item; K_ITEM *i_username, *i_workername, *i_diffdef, *i_oldworkers;
K_ITEM *u_item, *ua_item, *w_item;
HEARTBEATQUEUE *heartbeatqueue; HEARTBEATQUEUE *heartbeatqueue;
K_ITEM *hq_item; K_ITEM *hq_item;
char workername_buf[32]; // 'workername:' + digits char workername_buf[32]; // 'workername:' + digits
char diffdef_buf[32]; // 'difficultydefault:' + digits char diffdef_buf[32]; // 'difficultydefault:' + digits
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
USERATTS *useratts;
WORKERS *workers; WORKERS *workers;
USERS *users; USERS *users;
int32_t difficultydefault; int32_t difficultydefault;
@ -448,6 +473,37 @@ static char *cmd_workerset(PGconn *conn, char *cmd, char *id, tv_t *now,
// Default answer if no problems // Default answer if no problems
answer = strdup("updated"); answer = strdup("updated");
i_oldworkers = optional_name(trf_root, "oldworkers",
1, NULL, reply, siz);
if (i_oldworkers) {
bool update = false;
int64_t new_ow = atol(transfer_data(i_oldworkers));
K_RLOCK(useratts_free);
ua_item = find_useratts(users->userid, USER_OLD_WORKERS);
K_RUNLOCK(useratts_free);
if (!ua_item) {
if (new_ow != USER_OLD_WORKERS_DEFAULT)
update = true;
} else {
DATA_USERATTS(useratts, ua_item);
if (new_ow != useratts->attnum)
update = true;
}
if (update) {
ua_item = useratts_add(conn, users->username,
USER_OLD_WORKERS, EMPTY,
EMPTY, EMPTY,
transfer_data(i_oldworkers),
EMPTY, EMPTY, EMPTY,
by, code, inet, cd,
trf_root, false);
if (!ua_item)
reason = "Invalid";
}
goto kazuki;
}
// Loop through the list of workers and do any changes // Loop through the list of workers and do any changes
for (workernum = 0; workernum < 9999; workernum++) { for (workernum = 0; workernum < 9999; workernum++) {
snprintf(workername_buf, sizeof(workername_buf), snprintf(workername_buf, sizeof(workername_buf),
@ -524,6 +580,7 @@ static char *cmd_workerset(PGconn *conn, char *cmd, char *id, tv_t *now,
} }
} }
kazuki:
struckout: struckout:
if (reason) { if (reason) {
if (answer) if (answer)
@ -1201,7 +1258,7 @@ static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id,
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); i_username = adminuser(trf_root, reply, siz);
if (!i_username) if (!i_username)
return strdup(reply); return strdup(reply);
@ -1336,8 +1393,7 @@ static char *cmd_percent(char *cmd, char *id, tv_t *now, USERS *users)
DATA_WORKERS_NULL(workers, w_item); DATA_WORKERS_NULL(workers, w_item);
while (w_item && workers->userid == users->userid) { while (w_item && workers->userid == users->userid) {
if (CURRENT(&(workers->expirydate))) { if (CURRENT(&(workers->expirydate))) {
ws_item = find_workerstatus(users->userid, workers->workername, ws_item = get_workerstatus(users->userid, workers->workername);
__FILE__, __func__, __LINE__);
if (ws_item) { if (ws_item) {
DATA_WORKERSTATUS(workerstatus, ws_item); DATA_WORKERSTATUS(workerstatus, ws_item);
t_diffacc += workerstatus->diffacc; t_diffacc += workerstatus->diffacc;
@ -1520,10 +1576,13 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
WORKERS lookworkers, *workers; WORKERS lookworkers, *workers;
WORKERSTATUS *workerstatus; WORKERSTATUS *workerstatus;
USERSTATS *userstats; USERSTATS *userstats;
USERATTS *useratts;
USERS *users; USERS *users;
char reply[1024] = ""; char reply[1024] = "";
char tmp[1024]; char tmp[1024];
int64_t oldworkers = USER_OLD_WORKERS_DEFAULT;
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
tv_t last_share;
char *buf; char *buf;
size_t len, off; size_t len, off;
bool stats, percent; bool stats, percent;
@ -1531,7 +1590,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); i_username = adminuser(trf_root, reply, siz);
if (!i_username) if (!i_username)
return strdup(reply); return strdup(reply);
@ -1561,6 +1620,14 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
if (percent) if (percent)
return cmd_percent(cmd, id, now, users); return cmd_percent(cmd, id, now, users);
K_RLOCK(useratts_free);
ua_item = find_useratts(users->userid, USER_OLD_WORKERS);
K_RUNLOCK(useratts_free);
if (ua_item) {
DATA_USERATTS(useratts, ua_item);
oldworkers = useratts->attnum;
}
APPEND_REALLOC_INIT(buf, off, len); APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok."); APPEND_REALLOC(buf, off, len, "ok.");
snprintf(tmp, sizeof(tmp), "blockacc=%.1f%c", snprintf(tmp, sizeof(tmp), "blockacc=%.1f%c",
@ -1569,6 +1636,13 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
snprintf(tmp, sizeof(tmp), "blockreward=%"PRId64"%c", snprintf(tmp, sizeof(tmp), "blockreward=%"PRId64"%c",
pool.reward, FLDSEP); pool.reward, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "oldworkers=%"PRId64"%c",
oldworkers, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
if (oldworkers > 0)
oldworkers *= 24L * 60L * 60L;
else
oldworkers = now->tv_sec + 1;
INIT_WORKERS(&w_look); INIT_WORKERS(&w_look);
@ -1582,6 +1656,16 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
rows = 0; rows = 0;
while (w_item && workers->userid == users->userid) { while (w_item && workers->userid == users->userid) {
if (CURRENT(&(workers->expirydate))) { if (CURRENT(&(workers->expirydate))) {
ws_item = get_workerstatus(users->userid, workers->workername);
if (ws_item) {
DATA_WORKERSTATUS(workerstatus, ws_item);
K_RLOCK(workerstatus_free);
copy_tv(&last_share, &(workerstatus->last_share));
K_RUNLOCK(workerstatus_free);
} else
last_share.tv_sec = last_share.tv_usec = 0L;
if (tvdiff(now, &last_share) < oldworkers) {
str_to_buf(workers->workername, reply, sizeof(reply)); str_to_buf(workers->workername, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "workername:%d=%s%c", rows, reply, FLDSEP); snprintf(tmp, sizeof(tmp), "workername:%d=%s%c", rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
@ -1613,6 +1697,8 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
w_hashrate5m = w_hashrate1hr = w_hashrate5m = w_hashrate1hr =
w_hashrate24hr = 0.0; w_hashrate24hr = 0.0;
w_elapsed = -1; w_elapsed = -1;
if (!ws_item) {
w_lastshare.tv_sec = 0; w_lastshare.tv_sec = 0;
w_lastdiff = w_diffacc = w_diffinv = w_lastdiff = w_diffacc = w_diffinv =
w_diffsta = w_diffdup = w_diffsta = w_diffdup =
@ -1620,11 +1706,10 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
w_shareacc = w_shareinv = w_shareacc = w_shareinv =
w_sharesta = w_sharedup = w_sharesta = w_sharedup =
w_sharehi = w_sharerej = 0; w_sharehi = w_sharerej = 0;
} else {
ws_item = find_workerstatus(users->userid, workers->workername,
__FILE__, __func__, __LINE__);
if (ws_item) {
DATA_WORKERSTATUS(workerstatus, ws_item); DATA_WORKERSTATUS(workerstatus, ws_item);
// It's bad to read possibly changing data
K_RLOCK(workerstatus_free);
w_lastshare.tv_sec = workerstatus->last_share.tv_sec; w_lastshare.tv_sec = workerstatus->last_share.tv_sec;
w_lastdiff = workerstatus->last_diff; w_lastdiff = workerstatus->last_diff;
w_diffacc = workerstatus->diffacc; w_diffacc = workerstatus->diffacc;
@ -1639,6 +1724,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
w_sharedup = workerstatus->sharedup; w_sharedup = workerstatus->sharedup;
w_sharehi = workerstatus->sharehi; w_sharehi = workerstatus->sharehi;
w_sharerej = workerstatus->sharerej; w_sharerej = workerstatus->sharerej;
K_RUNLOCK(workerstatus_free);
} }
/* TODO: workers_root userid+worker is ordered /* TODO: workers_root userid+worker is ordered
@ -1731,9 +1817,9 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
snprintf(tmp, sizeof(tmp), "w_sharerej:%d=%s%c", rows, reply, FLDSEP); snprintf(tmp, sizeof(tmp), "w_sharerej:%d=%s%c", rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
} }
rows++; rows++;
} }
}
w_item = next_in_ktree(w_ctx); w_item = next_in_ktree(w_ctx);
DATA_WORKERS_NULL(workers, w_item); DATA_WORKERS_NULL(workers, w_item);
} }
@ -2164,9 +2250,9 @@ seconf:
return strdup("failed.DATA"); return strdup("failed.DATA");
} else { } else {
/* Don't slow down the reload - do them later /* Don't slow down the reload - do them later
* N.B. this means if you abort/shutdown the reload, * N.B. this means if you abort/terminate the reload,
* next restart will again go back to the oldest * next restart will again go back to the oldest
* unaged sharesummary due to a pool shutdown */ * unaged sharesummary due to a pool terminate */
if (!reloading) { if (!reloading) {
// Aging is a queued item thus the reply is ignored // Aging is a queued item thus the reply is ignored
auto_age_older(conn, workinfoid, auto_age_older(conn, workinfoid,
@ -4521,7 +4607,7 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id,
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); i_username = adminuser(trf_root, reply, siz);
if (!i_username) if (!i_username)
return strdup(reply); return strdup(reply);
@ -4616,30 +4702,118 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id,
return buf; return buf;
} }
/* Find the offset, in list, of the workername
* -1 means NULL list, empty list or not found */
static int worker_offset(char **list, char *workername)
{
char *c1, *c2;
int i;
if (!list || !(*list))
return -1;
/* Find the start of the workername including the SEP */
c1 = strchr(workername, WORKSEP1);
c2 = strchr(workername, WORKSEP2);
if (c1 || c2) {
if (!c1 || (c1 && c2 && (c2 < c1)))
c1 = c2;
}
// No workername after the username
if (!c1)
c1 = WORKERS_EMPTY;
for (i = 0; list[i]; i++) {
if (strcmp(c1, list[i]) == 0)
return i;
}
return -1;
}
/* Some arbitrarily large limit, increase it if needed
(doesn't need to be very large) */
#define SELECT_LIMIT 63
/* select is a string of workernames separated by WORKERS_SEL_SEP
* Return an array of strings of select broken up
* The array is terminated by NULL
* and will have 0 elements if select is NULL/empty
* The count of the first occurrence of WORKERS_ALL is returned in *all_count,
* or -1 if WORKERS_ALL isn't found */
static char **select_list(char *select, int *all_count)
{
size_t len, offset, siz;
char **list = NULL;
int count;
char *end;
*all_count = -1;
siz = sizeof(char *) * (SELECT_LIMIT + 1);
list = malloc(siz);
if (!list)
quithere(1, "malloc (%d) OOM", (int)siz);
list[0] = NULL;
if (select == NULL || *select == '\0')
return list;
len = strlen(select);
count = 0;
offset = 0;
while (offset < len) {
if (select[offset] == WORKERS_SEL_SEP)
offset++;
else {
list[count] = select + offset;
list[count+1] = NULL;
end = strchr(list[count], WORKERS_SEL_SEP);
if (end != NULL) {
offset = 1 + end - select;
*end = '\0';
}
if (*all_count == -1 &&
strcasecmp(list[count], WORKERS_ALL) == 0) {
*all_count = count;
}
if (end == NULL || ++count > SELECT_LIMIT)
break;
}
}
return list;
}
static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id, static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
__maybe_unused tv_t *now, __maybe_unused char *by, tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet, __maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, __maybe_unused tv_t *notcd, K_TREE *trf_root)
__maybe_unused K_TREE *trf_root)
{ {
K_ITEM *i_username, *u_item, *m_item, ms_look, *wm_item, *ms_item, *wi_item; K_ITEM *i_username, *i_select;
K_ITEM *u_item, *p_item, *m_item, ms_look, *wm_item, *ms_item, *wi_item;
K_TREE_CTX wm_ctx[1], ms_ctx[1]; K_TREE_CTX wm_ctx[1], ms_ctx[1];
WORKMARKERS *wm; WORKMARKERS *wm;
WORKINFO *wi; WORKINFO *wi;
MARKERSUMMARY markersummary, *ms, ms_add; MARKERSUMMARY markersummary, *ms, ms_add;
PAYOUTS *payouts;
USERS *users; USERS *users;
MARKS *marks = NULL; MARKS *marks = NULL;
char reply[1024] = ""; char reply[1024] = "";
char tmp[1024]; char tmp[1024];
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
char *select = NULL;
char **selects = NULL;
bool used[SELECT_LIMIT];
char *buf; char *buf;
size_t len, off; size_t len, off;
tv_t marker_end = { 0L, 0L }; tv_t marker_end = { 0L, 0L };
int rows; int rows, want, i, where_all;
int64_t maxrows;
double wm_count;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); i_username = adminuser(trf_root, reply, siz);
if (!i_username) if (!i_username)
return strdup(reply); return strdup(reply);
@ -4650,6 +4824,36 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
return strdup("bad"); return strdup("bad");
DATA_USERS(users, u_item); DATA_USERS(users, u_item);
maxrows = user_sys_setting(users->userid, SHIFTS_SETTING_NAME,
SHIFTS_DEFAULT, now);
K_RLOCK(payouts_free);
p_item = find_last_payouts();
K_RUNLOCK(payouts_free);
if (p_item) {
DATA_PAYOUTS(payouts, p_item);
wm_count = payout_stats(payouts, "wm_count");
wm_count *= 1.42;
if (maxrows < wm_count)
maxrows = wm_count;
}
i_select = optional_name(trf_root, "select", 1, NULL, reply, siz);
if (i_select)
select = strdup(transfer_data(i_select));
selects = select_list(select, &where_all);
// Nothing selected = all
if (*selects == NULL) {
where_all = 0;
selects[0] = WORKERS_ALL;
selects[1] = NULL;
}
bzero(used, sizeof(used));
if (where_all >= 0)
used[where_all] = true;
APPEND_REALLOC_INIT(buf, off, len); APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok."); APPEND_REALLOC(buf, off, len, "ok.");
INIT_MARKERSUMMARY(&ms_look); INIT_MARKERSUMMARY(&ms_look);
@ -4660,7 +4864,7 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
DATA_WORKMARKERS_NULL(wm, wm_item); DATA_WORKMARKERS_NULL(wm, wm_item);
/* TODO: allow to see details of a single payoutid /* TODO: allow to see details of a single payoutid
* if it has multiple items (percent payout user) */ * if it has multiple items (percent payout user) */
while (rows < 98 && wm_item) { while (rows < (maxrows - 1) && wm_item) {
if (CURRENT(&(wm->expirydate)) && WMPROCESSED(wm->status)) { if (CURRENT(&(wm->expirydate)) && WMPROCESSED(wm->status)) {
K_RUNLOCK(workmarkers_free); K_RUNLOCK(workmarkers_free);
@ -4693,6 +4897,30 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
ms_add.shareacc += ms->shareacc; ms_add.shareacc += ms->shareacc;
ms_add.sharerej += ms->sharerej; ms_add.sharerej += ms->sharerej;
want = worker_offset(selects, ms->workername);
if (want >= 0) {
used[want] = true;
double_to_buf(ms->diffacc, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_diffacc:%d=%s%c",
want, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms->diffrej, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_diffrej:%d=%s%c",
want, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms->shareacc, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_shareacc:%d=%s%c",
want, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms->sharerej, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_sharerej:%d=%s%c",
want, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
}
ms_item = next_in_ktree(ms_ctx); ms_item = next_in_ktree(ms_ctx);
DATA_MARKERSUMMARY_NULL(ms, ms_item); DATA_MARKERSUMMARY_NULL(ms, ms_item);
} }
@ -4712,7 +4940,9 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
wm->description, wm->description,
wm->workinfoidend); wm->workinfoidend);
snprintf(reply, siz, "data error 1"); snprintf(reply, siz, "data error 1");
return strdup(reply); free(buf);
free(selects);
return(strdup(reply));
} }
DATA_WORKINFO(wi, wi_item); DATA_WORKINFO(wi, wi_item);
copy_tv(&marker_end, &(wi->createdate)); copy_tv(&marker_end, &(wi->createdate));
@ -4731,7 +4961,9 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
__func__, wm->markerid, wm->description, __func__, wm->markerid, wm->description,
wm->workinfoidstart); wm->workinfoidstart);
snprintf(reply, siz, "data error 2"); snprintf(reply, siz, "data error 2");
return strdup(reply); free(buf);
free(selects);
return(strdup(reply));
} }
DATA_WORKINFO(wi, wi_item); DATA_WORKINFO(wi, wi_item);
@ -4761,26 +4993,31 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
rows, reply, FLDSEP); rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
if (where_all >= 0) {
double_to_buf(ms_add.diffacc, reply, sizeof(reply)); double_to_buf(ms_add.diffacc, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "diffacc:%d=%s%c", snprintf(tmp, sizeof(tmp), "%d_diffacc:%d=%s%c",
rows, reply, FLDSEP); where_all, rows,
reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms_add.diffrej, reply, sizeof(reply)); double_to_buf(ms_add.diffrej, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "diffrej:%d=%s%c", snprintf(tmp, sizeof(tmp), "%d_diffrej:%d=%s%c",
rows, reply, FLDSEP); where_all, rows,
reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms_add.shareacc, reply, sizeof(reply)); double_to_buf(ms_add.shareacc, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "shareacc:%d=%s%c", snprintf(tmp, sizeof(tmp), "%d_shareacc:%d=%s%c",
rows, reply, FLDSEP); where_all, rows,
reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms_add.sharerej, reply, sizeof(reply)); double_to_buf(ms_add.sharerej, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "sharerej:%d=%s%c", snprintf(tmp, sizeof(tmp), "%d_sharerej:%d=%s%c",
rows, reply, FLDSEP); where_all, rows,
reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
}
rows++; rows++;
// Setup for next shift // Setup for next shift
@ -4793,17 +5030,55 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
} }
K_RUNLOCK(workmarkers_free); K_RUNLOCK(workmarkers_free);
for (i = 0; selects[i]; i++) {
if (used[i]) {
snprintf(tmp, sizeof(tmp),
"%d_worker=%s%c",
i, selects[i], FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp),
"%d_flds=%s%c", i,
"diffacc,diffrej,shareacc,sharerej", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
}
}
// Missing if all isn't selected
if (where_all >= 0) {
snprintf(tmp, sizeof(tmp), "prefix_all=%d_%c",
where_all, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
}
/* rows is an upper limit of rows in each worker
* 'all' starts at 0 and finishes at rows-1
* other workers start >= 0 and finish <= rows-1 */
snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c", snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c",
rows, FLDSEP, rows, FLDSEP,
"markerid,shift,start,end,diffacc,diffrej,shareacc,sharerej", "markerid,shift,start,end", FLDSEP);
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Shifts", FLDSEP, ""); snprintf(tmp, sizeof(tmp), "arn=%s", "Shifts");
APPEND_REALLOC(buf, off, len, tmp);
for (i = 0; selects[i]; i++) {
if (used[i]) {
snprintf(tmp, sizeof(tmp), ",Worker_%d", i);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
}
}
snprintf(tmp, sizeof(tmp), "%carp=", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
for (i = 0; selects[i]; i++) {
if (used[i]) {
snprintf(tmp, sizeof(tmp), ",%d_", i);
APPEND_REALLOC(buf, off, len, tmp);
}
}
LOGDEBUG("%s.ok.%s", id, transfer_data(i_username)); LOGDEBUG("%s.ok.%s", id, transfer_data(i_username));
return buf; free(selects);
return(buf);
} }
static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd,
@ -4902,10 +5177,14 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id,
USEINFO(idcontrol, 1, 0); USEINFO(idcontrol, 1, 0);
USEINFO(optioncontrol, 1, 1); USEINFO(optioncontrol, 1, 1);
USEINFO(workinfo, 1, 1); USEINFO(workinfo, 1, 1);
USEINFO(shares, 1, 1); // Trees don't share items so count as 1 tree
USEINFO(shareerrors, 1, 1); USEINFO(shares, 2, 1);
// Trees don't share items so count as 1 tree
USEINFO(shareerrors, 2, 1);
// _pool doesn't share items so is included
USEINFO(sharesummary, 1, 2); USEINFO(sharesummary, 1, 2);
USEINFO(workmarkers, 1, 2); USEINFO(workmarkers, 1, 2);
// _pool doesn't share items so is included
USEINFO(markersummary, 1, 2); USEINFO(markersummary, 1, 2);
USEINFO(marks, 1, 1); USEINFO(marks, 1, 1);
USEINFO(blocks, 1, 1); USEINFO(blocks, 1, 1);
@ -5361,6 +5640,208 @@ dame:
return strdup(reply); return strdup(reply);
} }
// Layout the reply like cmd_shifts so the php/js code is similar
static char *cmd_pshift(__maybe_unused PGconn *conn, char *cmd, char *id,
tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root)
{
K_ITEM *i_username;
K_ITEM *u_item, *p_item, *m_item, *wm_item, *ms_item, *wi_item;
K_TREE_CTX wm_ctx[1];
WORKMARKERS *wm;
WORKINFO *wi;
MARKERSUMMARY *ms;
PAYOUTS *payouts;
USERS *users;
MARKS *marks = NULL;
char reply[1024] = "";
char tmp[1024];
size_t siz = sizeof(reply);
char *buf;
size_t len, off;
tv_t marker_end = { 0L, 0L };
int rows;
int64_t maxrows;
double wm_count;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = adminuser(trf_root, reply, siz);
if (!i_username)
return strdup(reply);
K_RLOCK(users_free);
u_item = find_users(transfer_data(i_username));
K_RUNLOCK(users_free);
if (!u_item)
return strdup("bad");
DATA_USERS(users, u_item);
maxrows = user_sys_setting(users->userid, SHIFTS_SETTING_NAME,
SHIFTS_DEFAULT, now);
K_RLOCK(payouts_free);
p_item = find_last_payouts();
K_RUNLOCK(payouts_free);
if (p_item) {
DATA_PAYOUTS(payouts, p_item);
wm_count = payout_stats(payouts, "wm_count");
wm_count *= 1.42;
if (maxrows < wm_count)
maxrows = wm_count;
}
APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok.");
rows = 0;
K_RLOCK(workmarkers_free);
wm_item = last_in_ktree(workmarkers_workinfoid_root, wm_ctx);
DATA_WORKMARKERS_NULL(wm, wm_item);
while (rows < (maxrows - 1) && wm_item) {
if (CURRENT(&(wm->expirydate)) && WMPROCESSED(wm->status)) {
K_RUNLOCK(workmarkers_free);
K_RLOCK(marks_free);
m_item = find_marks(wm->workinfoidend);
K_RUNLOCK(marks_free);
DATA_MARKS_NULL(marks, m_item);
if (m_item == NULL) {
// Log it but keep going
LOGERR("%s() missing mark for markerid "
"%"PRId64"/%s widend %"PRId64,
__func__, wm->markerid,
wm->description,
wm->workinfoidend);
}
K_RLOCK(markersummary_free);
ms_item = find_markersummary_p(wm->markerid);
K_RUNLOCK(markersummary_free);
if (ms_item) {
DATA_MARKERSUMMARY(ms, ms_item);
double_to_buf(ms->diffacc, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_diffacc:%d=%s%c",
0, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms->diffrej, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_diffrej:%d=%s%c",
0, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms->shareacc, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_shareacc:%d=%s%c",
0, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
double_to_buf(ms->sharerej, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "%d_sharerej:%d=%s%c",
0, rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
}
if (marker_end.tv_sec == 0L) {
wi_item = next_workinfo(wm->workinfoidend, NULL);
if (!wi_item) {
/* There's no workinfo after this shift
* Unexpected ... estimate last wid+30s */
wi_item = find_workinfo(wm->workinfoidend, NULL);
if (!wi_item) {
// Nothing is currently locked
LOGERR("%s() workmarker %"PRId64"/%s."
" missing widend %"PRId64,
__func__, wm->markerid,
wm->description,
wm->workinfoidend);
snprintf(reply, siz, "data error 1");
free(buf);
return(strdup(reply));
}
DATA_WORKINFO(wi, wi_item);
copy_tv(&marker_end, &(wi->createdate));
marker_end.tv_sec += 30;
} else {
DATA_WORKINFO(wi, wi_item);
copy_tv(&marker_end, &(wi->createdate));
}
}
wi_item = find_workinfo(wm->workinfoidstart, NULL);
if (!wi_item) {
// Nothing is currently locked
LOGERR("%s() workmarker %"PRId64"/%s. missing "
"widstart %"PRId64,
__func__, wm->markerid, wm->description,
wm->workinfoidstart);
snprintf(reply, siz, "data error 2");
free(buf);
return(strdup(reply));
}
DATA_WORKINFO(wi, wi_item);
bigint_to_buf(wm->markerid, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "markerid:%d=%s%c",
rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
str_to_buf(wm->description, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "shift:%d=%s%c",
rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "endmarkextra:%d=%s%c",
rows,
m_item ? marks->extra : EMPTY,
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
ftv_to_buf(&(wi->createdate), reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "start:%d=%s%c",
rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
ftv_to_buf(&marker_end, reply, sizeof(reply));
snprintf(tmp, sizeof(tmp), "end:%d=%s%c",
rows, reply, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
rows++;
// Setup for next shift
copy_tv(&marker_end, &(wi->createdate));
K_RLOCK(workmarkers_free);
}
wm_item = prev_in_ktree(wm_ctx);
DATA_WORKMARKERS_NULL(wm, wm_item);
}
K_RUNLOCK(workmarkers_free);
snprintf(tmp, sizeof(tmp), "%d_pool=%s%c", 0, "all", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "%d_flds=%s%c",
0, "diffacc,diffrej,shareacc,sharerej", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "prefix_all=%d_%c", 0, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c",
rows, FLDSEP,
"markerid,shift,start,end", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "arn=%s", "Pool Shifts");
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), ",Pool_%d", 0);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "%carp=", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), ",%d_", 0);
APPEND_REALLOC(buf, off, len, tmp);
LOGDEBUG("%s.ok.%s", id, transfer_data(i_username));
return(buf);
}
// TODO: limit access by having seperate sockets for each // TODO: limit access by having seperate sockets for each
#define ACCESS_POOL "p" #define ACCESS_POOL "p"
#define ACCESS_SYSTEM "s" #define ACCESS_SYSTEM "s"
@ -5399,7 +5880,7 @@ dame:
* ping * ping
* .STAMP.ok.pong * .STAMP.ok.pong
* *
* shutdown * terminate
* .STAMP.ok.exiting * .STAMP.ok.exiting
* *
* With an ID * With an ID
@ -5429,7 +5910,7 @@ dame:
// cmd_val cmd_str noid createdate func access // cmd_val cmd_str noid createdate func access
struct CMDS ckdb_cmds[] = { struct CMDS ckdb_cmds[] = {
{ CMD_SHUTDOWN, "shutdown", true, false, NULL, ACCESS_SYSTEM }, { CMD_TERMINATE, "terminate", true, false, NULL, ACCESS_SYSTEM },
{ CMD_PING, "ping", true, false, NULL, ACCESS_SYSTEM ACCESS_POOL ACCESS_WEB }, { CMD_PING, "ping", true, false, NULL, ACCESS_SYSTEM ACCESS_POOL ACCESS_WEB },
{ CMD_VERSION, "version", true, false, NULL, ACCESS_SYSTEM ACCESS_POOL ACCESS_WEB }, { CMD_VERSION, "version", true, false, NULL, ACCESS_SYSTEM ACCESS_POOL ACCESS_WEB },
{ CMD_LOGLEVEL, "loglevel", true, false, NULL, ACCESS_SYSTEM }, { CMD_LOGLEVEL, "loglevel", true, false, NULL, ACCESS_SYSTEM },
@ -5471,5 +5952,6 @@ struct CMDS ckdb_cmds[] = {
{ CMD_SHIFTS, "shifts", false, false, cmd_shifts, ACCESS_SYSTEM ACCESS_WEB }, { CMD_SHIFTS, "shifts", false, false, cmd_shifts, ACCESS_SYSTEM ACCESS_WEB },
{ CMD_USERSTATUS,"userstatus", false, false, cmd_userstatus, ACCESS_SYSTEM ACCESS_WEB }, { CMD_USERSTATUS,"userstatus", false, false, cmd_userstatus, ACCESS_SYSTEM ACCESS_WEB },
{ CMD_MARKS, "marks", false, false, cmd_marks, ACCESS_SYSTEM }, { CMD_MARKS, "marks", false, false, cmd_marks, ACCESS_SYSTEM },
{ CMD_PSHIFT, "pshift", false, false, cmd_pshift, ACCESS_SYSTEM ACCESS_WEB },
{ CMD_END, NULL, false, false, NULL, NULL } { CMD_END, NULL, false, false, NULL, NULL }
}; };

268
src/ckdb_data.c

@ -417,6 +417,14 @@ char *_data_to_buf(enum data_type typ, void *data, char *buf, size_t siz, WHERE_
tm.tm_sec, tm.tm_sec,
(((tv_t *)data)->tv_usec)); (((tv_t *)data)->tv_usec));
break; break;
case TYPE_BTV:
gmtime_r(&(((tv_t *)data)->tv_sec), &tm);
snprintf(buf, siz, "%02d %02d:%02d:%02d",
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec);
break;
case TYPE_CTV: case TYPE_CTV:
snprintf(buf, siz, "%ld,%ld", snprintf(buf, siz, "%ld,%ld",
(((tv_t *)data)->tv_sec), (((tv_t *)data)->tv_sec),
@ -476,6 +484,12 @@ char *_tvs_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS)
return _data_to_buf(TYPE_TVS, (void *)data, buf, siz, WHERE_FFL_PASS); return _data_to_buf(TYPE_TVS, (void *)data, buf, siz, WHERE_FFL_PASS);
} }
// Convert tv to (brief) DD HH:MM:SS
char *_btv_to_buf(tv_t *data, char *buf, size_t siz, WHERE_FFL_ARGS)
{
return _data_to_buf(TYPE_BTV, (void *)data, buf, siz, WHERE_FFL_PASS);
}
/* unused yet /* unused yet
char *_blob_to_buf(char *data, char *buf, size_t siz, WHERE_FFL_ARGS) char *_blob_to_buf(char *data, char *buf, size_t siz, WHERE_FFL_ARGS)
{ {
@ -695,8 +709,10 @@ K_ITEM *get_workerstatus(int64_t userid, char *workername)
/* Worker loading/creation calls this with create = true /* Worker loading/creation calls this with create = true
* All others with create = false since the workerstatus should exist * All others with create = false since the workerstatus should exist
* Failure is a code bug and a reported error, but handled anyway * If it is missing, it will check for and create the worker if needed
* and create a new workerstatus and return it
* This has 2 sets of file/func/line to allow 2 levels of traceback * This has 2 sets of file/func/line to allow 2 levels of traceback
* to see why it happened
*/ */
K_ITEM *_find_create_workerstatus(int64_t userid, char *workername, K_ITEM *_find_create_workerstatus(int64_t userid, char *workername,
bool create, const char *file2, bool create, const char *file2,
@ -704,90 +720,83 @@ K_ITEM *_find_create_workerstatus(int64_t userid, char *workername,
WHERE_FFL_ARGS) WHERE_FFL_ARGS)
{ {
WORKERSTATUS *row; WORKERSTATUS *row;
K_ITEM *item; K_ITEM *ws_item, *w_item = NULL;
bool ws_err = false, w_err = false;
tv_t now;
item = get_workerstatus(userid, workername); ws_item = get_workerstatus(userid, workername);
if (!item) { if (!ws_item) {
if (!create) { if (!create) {
LOGEMERG("%s(): Missing workerstatus %"PRId64"/%s" ws_err = true;
WHERE_FFL WHERE_FFL,
__func__, userid, workername, w_item = find_workers(userid, workername);
file2, func2, line2, WHERE_FFL_PASS); if (!w_item) {
return NULL; w_err = true;
setnow(&now);
w_item = workers_add(NULL, userid, workername,
NULL, NULL, NULL,
by_default,
(char *)__func__,
(char *)inet_default,
&now, NULL);
}
} }
K_WLOCK(workerstatus_free); K_WLOCK(workerstatus_free);
item = k_unlink_head(workerstatus_free); ws_item = k_unlink_head(workerstatus_free);
DATA_WORKERSTATUS(row, item); DATA_WORKERSTATUS(row, ws_item);
bzero(row, sizeof(*row)); bzero(row, sizeof(*row));
row->userid = userid; row->userid = userid;
STRNCPY(row->workername, workername); STRNCPY(row->workername, workername);
workerstatus_root = add_to_ktree(workerstatus_root, item, cmp_workerstatus); workerstatus_root = add_to_ktree(workerstatus_root, ws_item, cmp_workerstatus);
k_add_head(workerstatus_store, item); k_add_head(workerstatus_store, ws_item);
K_WUNLOCK(workerstatus_free); K_WUNLOCK(workerstatus_free);
if (ws_err) {
LOGERR("%s(): CREATED Missing workerstatus %"PRId64"/%s"
WHERE_FFL WHERE_FFL,
__func__, userid, workername,
file2, func2, line2, WHERE_FFL_PASS);
if (w_err) {
LOGERR("%s(): %s Missing worker %"PRId64"/%s",
__func__,
w_item ? "CREATED" : "FAILED TO CREATE",
userid, workername);
} }
return item; }
}
return ws_item;
} }
/* All data is loaded, now update workerstatus fields /* All data is loaded, now update workerstatus fields
TODO: combine set_block_share_counters() with this? */ TODO: combine set_block_share_counters() with this? */
void workerstatus_ready() void workerstatus_ready()
{ {
K_TREE_CTX ws_ctx[1], ss_ctx[1], ms_ctx[1]; K_TREE_CTX ws_ctx[1];
K_ITEM *ws_item, us_look, ss_look, *us_item, *ss_item; K_ITEM *ws_item, *ms_item, *ss_item;
K_ITEM *ms_item, ms_look, *wm_item;
USERSTATS *userstats;
SHARESUMMARY looksharesummary, *sharesummary;
MARKERSUMMARY *markersummary;
WORKERSTATUS *workerstatus; WORKERSTATUS *workerstatus;
MARKERSUMMARY *markersummary;
SHARESUMMARY *sharesummary;
LOGWARNING("%s(): Updating workerstatus...", __func__); LOGWARNING("%s(): Updating workerstatus...", __func__);
INIT_USERSTATS(&us_look);
INIT_MARKERSUMMARY(&ms_look);
INIT_SHARESUMMARY(&ss_look);
ws_item = first_in_ktree(workerstatus_root, ws_ctx); ws_item = first_in_ktree(workerstatus_root, ws_ctx);
while (ws_item) { while (ws_item) {
DATA_WORKERSTATUS(workerstatus, ws_item); DATA_WORKERSTATUS(workerstatus, ws_item);
// Zero or one
K_RLOCK(userstats_free);
us_item = find_userstats(workerstatus->userid,
workerstatus->workername);
K_RUNLOCK(userstats_free);
if (us_item) {
DATA_USERSTATS(userstats, us_item);
if (userstats->idle) {
if (tv_newer(&(workerstatus->last_idle),
&(userstats->statsdate))) {
copy_tv(&(workerstatus->last_idle),
&(userstats->statsdate));
}
} else {
if (tv_newer(&(workerstatus->last_stats),
&(userstats->statsdate))) {
copy_tv(&(workerstatus->last_stats),
&(userstats->statsdate));
}
}
}
K_RLOCK(markersummary_free); K_RLOCK(markersummary_free);
// This is the last one // This is the last share datestamp
ms_item = find_markersummary_userid(workerstatus->userid, ms_item = find_markersummary_userid(workerstatus->userid,
workerstatus->workername, ms_ctx); workerstatus->workername,
NULL);
K_RUNLOCK(markersummary_free); K_RUNLOCK(markersummary_free);
if (ms_item) { if (ms_item) {
DATA_MARKERSUMMARY(markersummary, ms_item); DATA_MARKERSUMMARY(markersummary, ms_item);
K_RLOCK(workmarkers_free); if (tv_newer(&(workerstatus->last_share),
wm_item = find_workmarkerid(markersummary->markerid, &(markersummary->lastshare))) {
false, MARKER_PROCESSED);
K_RUNLOCK(workmarkers_free);
if (wm_item &&
tv_newer(&(workerstatus->last_share), &(markersummary->lastshare))) {
copy_tv(&(workerstatus->last_share), copy_tv(&(workerstatus->last_share),
&(markersummary->lastshare)); &(markersummary->lastshare));
workerstatus->last_diff = workerstatus->last_diff =
@ -795,14 +804,9 @@ void workerstatus_ready()
} }
} }
// The last one
looksharesummary.userid = workerstatus->userid;
looksharesummary.workername = workerstatus->workername;
looksharesummary.workinfoid = MAXID;
ss_look.data = (void *)(&looksharesummary);
K_RLOCK(sharesummary_free); K_RLOCK(sharesummary_free);
ss_item = find_before_in_ktree(sharesummary_root, &ss_look, ss_item = find_last_sharesummary(workerstatus->userid,
cmp_sharesummary, ss_ctx); workerstatus->workername);
K_RUNLOCK(sharesummary_free); K_RUNLOCK(sharesummary_free);
if (ss_item) { if (ss_item) {
DATA_SHARESUMMARY(sharesummary, ss_item); DATA_SHARESUMMARY(sharesummary, ss_item);
@ -1512,6 +1516,43 @@ K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height)
return best; return best;
} }
/*
* Get a setting value for the given setting name
* First check if there is a USERATTS attnum value != 0
* If not, check if there is an OPTIONCONTROL record (can be any value)
* If not, return the default
* WARNING OPTIONCONTROL is time dependent,
* i.e. ensure now and pool.height are correct (e.g. during a reload)
*/
int64_t user_sys_setting(int64_t userid, char *setting_name,
int64_t setting_default, tv_t *now)
{
OPTIONCONTROL *optioncontrol;
K_ITEM *ua_item, *oc_item;
USERATTS *useratts;
if (userid != 0) {
K_RLOCK(useratts_free);
ua_item = find_useratts(userid, setting_name);
K_RUNLOCK(useratts_free);
if (ua_item) {
DATA_USERATTS(useratts, ua_item);
if (useratts->attnum != 0)
return useratts->attnum;
}
}
K_RLOCK(optioncontrol_free);
oc_item = find_optioncontrol(setting_name, now, pool.height);
K_RUNLOCK(optioncontrol_free);
if (oc_item) {
DATA_OPTIONCONTROL(optioncontrol, oc_item);
return (int64_t)atol(optioncontrol->optionvalue);
}
return setting_default;
}
// order by workinfoid asc,expirydate asc // order by workinfoid asc,expirydate asc
cmp_t cmp_workinfo(K_ITEM *a, K_ITEM *b) cmp_t cmp_workinfo(K_ITEM *a, K_ITEM *b)
{ {
@ -1902,7 +1943,7 @@ void zero_sharesummary(SHARESUMMARY *row, tv_t *cd, double diff)
row->complete[1] = '\0'; row->complete[1] = '\0';
} }
K_ITEM *find_sharesummary(int64_t userid, char *workername, int64_t workinfoid) K_ITEM *_find_sharesummary(int64_t userid, char *workername, int64_t workinfoid, bool pool)
{ {
SHARESUMMARY sharesummary; SHARESUMMARY sharesummary;
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
@ -1914,7 +1955,35 @@ K_ITEM *find_sharesummary(int64_t userid, char *workername, int64_t workinfoid)
INIT_SHARESUMMARY(&look); INIT_SHARESUMMARY(&look);
look.data = (void *)(&sharesummary); look.data = (void *)(&sharesummary);
return find_in_ktree(sharesummary_root, &look, cmp_sharesummary, ctx); if (pool) {
return find_in_ktree(sharesummary_pool_root, &look,
cmp_sharesummary, ctx);
} else {
return find_in_ktree(sharesummary_root, &look,
cmp_sharesummary, ctx);
}
}
K_ITEM *find_last_sharesummary(int64_t userid, char *workername)
{
SHARESUMMARY look_sharesummary, *sharesummary;
K_TREE_CTX ctx[1];
K_ITEM look, *item;
look_sharesummary.userid = userid;
look_sharesummary.workername = workername;
look_sharesummary.workinfoid = MAXID;
INIT_SHARESUMMARY(&look);
look.data = (void *)(&look_sharesummary);
item = find_before_in_ktree(sharesummary_root, &look, cmp_sharesummary, ctx);
if (item) {
DATA_SHARESUMMARY(sharesummary, item);
if (sharesummary->userid != userid ||
strcmp(sharesummary->workername, workername) != 0)
item = NULL;
}
return item;
} }
/* TODO: markersummary checking? /* TODO: markersummary checking?
@ -2695,7 +2764,7 @@ K_ITEM *find_last_payouts()
return p_item; return p_item;
p_item = prev_in_ktree(ctx); p_item = prev_in_ktree(ctx);
} }
return p_item; return NULL;
} }
K_ITEM *find_payoutid(int64_t payoutid) K_ITEM *find_payoutid(int64_t payoutid)
@ -2713,6 +2782,43 @@ K_ITEM *find_payoutid(int64_t payoutid)
return find_in_ktree(payouts_id_root, &look, cmp_payouts_id, ctx); return find_in_ktree(payouts_id_root, &look, cmp_payouts_id, ctx);
} }
/* Values from payout stats, returns -1 if statname isn't found
* If code needs a value then it probably really should be a new payouts field
* rather than stored in the stats passed to the pplns2 web page
* but anyway ... */
double payout_stats(PAYOUTS *payouts, char *statname)
{
char buf[1024]; // If a number is bigger than this ... bad luck
double ret = -1.0;
size_t numlen, len = strlen(statname);
char *pos, *tab;
pos = payouts->stats;
while (pos && *pos) {
if (strncmp(pos, statname, len) == 0 && pos[len] == '=') {
pos += len+1;
// They should only contain +ve numbers
if (*pos && isdigit(*pos)) {
tab = strchr(pos, '\t');
if (!tab)
numlen = strlen(pos);
else
numlen = tab - pos;
if (numlen >= sizeof(buf))
numlen = sizeof(buf) - 1;
STRNCPYSIZ(buf, pos, numlen+1);
// ctv will only return the seconds
ret = atof(buf);
}
break;
}
pos = strchr(pos, '\t');
if (pos)
pos++;
}
return ret;
}
/* Find the block_workinfoid of the block requested /* Find the block_workinfoid of the block requested
then add all it's diffacc shares then add all it's diffacc shares
then keep stepping back shares until diffacc_total matches or exceeds then keep stepping back shares until diffacc_total matches or exceeds
@ -3563,7 +3669,7 @@ void dsp_markersummary(K_ITEM *item, FILE *stream)
} }
} }
// order by markerid asc,userid asc,workername asc // order by markerid asc,userid asc,workername asc (has no expirydate)
cmp_t cmp_markersummary(K_ITEM *a, K_ITEM *b) cmp_t cmp_markersummary(K_ITEM *a, K_ITEM *b)
{ {
MARKERSUMMARY *ma, *mb; MARKERSUMMARY *ma, *mb;
@ -3578,7 +3684,7 @@ cmp_t cmp_markersummary(K_ITEM *a, K_ITEM *b)
return c; return c;
} }
// order by userid asc,workername asc,lastshare asc // order by userid asc,workername asc,lastshare asc (has no expirydate)
cmp_t cmp_markersummary_userid(K_ITEM *a, K_ITEM *b) cmp_t cmp_markersummary_userid(K_ITEM *a, K_ITEM *b)
{ {
MARKERSUMMARY *ma, *mb; MARKERSUMMARY *ma, *mb;
@ -3593,12 +3699,17 @@ cmp_t cmp_markersummary_userid(K_ITEM *a, K_ITEM *b)
return c; return c;
} }
// Finds the last markersummary for the worker but also returns the CTX // Finds the last markersummary for the worker and optionally return the CTX
K_ITEM *find_markersummary_userid(int64_t userid, char *workername, K_TREE_CTX *ctx) K_ITEM *find_markersummary_userid(int64_t userid, char *workername,
K_TREE_CTX *ctx)
{ {
K_TREE_CTX ctx0[1];
K_ITEM look, *ms_item = NULL; K_ITEM look, *ms_item = NULL;
MARKERSUMMARY markersummary, *ms; MARKERSUMMARY markersummary, *ms;
if (ctx == NULL)
ctx = ctx0;
markersummary.userid = userid; markersummary.userid = userid;
markersummary.workername = workername; markersummary.workername = workername;
markersummary.lastshare.tv_sec = DATE_S_EOT; markersummary.lastshare.tv_sec = DATE_S_EOT;
@ -3614,23 +3725,40 @@ K_ITEM *find_markersummary_userid(int64_t userid, char *workername, K_TREE_CTX *
return ms_item; return ms_item;
} }
K_ITEM *find_markersummary(int64_t workinfoid, int64_t userid, char *workername) K_ITEM *_find_markersummary(int64_t markerid, int64_t workinfoid,
int64_t userid, char *workername, bool pool)
{ {
K_ITEM look, *wm_item, *ms_item = NULL; K_ITEM look, *wm_item, *ms_item = NULL;
MARKERSUMMARY markersummary; MARKERSUMMARY markersummary;
WORKMARKERS *wm; WORKMARKERS *wm;
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
if (markerid == 0) {
wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED); wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED);
if (wm_item) { if (wm_item) {
DATA_WORKMARKERS(wm, wm_item); DATA_WORKMARKERS(wm, wm_item);
markersummary.markerid = wm->markerid; markerid = wm->markerid;
}
} else {
wm_item = find_workmarkerid(markerid, false, MARKER_PROCESSED);
if (!wm_item)
markerid = 0;
}
if (markerid != 0) {
markersummary.markerid = markerid;
markersummary.userid = userid; markersummary.userid = userid;
markersummary.workername = workername; markersummary.workername = workername;
INIT_MARKERSUMMARY(&look); INIT_MARKERSUMMARY(&look);
look.data = (void *)(&markersummary); look.data = (void *)(&markersummary);
ms_item = find_in_ktree(markersummary_root, &look, cmp_markersummary, ctx); if (pool) {
ms_item = find_in_ktree(markersummary_pool_root, &look,
cmp_markersummary, ctx);
} else {
ms_item = find_in_ktree(markersummary_root, &look,
cmp_markersummary, ctx);
}
} }
return ms_item; return ms_item;

1044
src/ckdb_dbio.c

File diff suppressed because it is too large Load Diff

88
src/stratifier.c

@ -347,6 +347,45 @@ struct session {
time_t added; time_t added;
}; };
#define ID_AUTH 0
#define ID_WORKINFO 1
#define ID_AGEWORKINFO 2
#define ID_SHARES 3
#define ID_SHAREERR 4
#define ID_POOLSTATS 5
#define ID_WORKERSTATS 6
#define ID_BLOCK 7
#define ID_ADDRAUTH 8
#define ID_HEARTBEAT 9
static const char *ckdb_ids[] = {
"authorise",
"workinfo",
"ageworkinfo",
"shares",
"shareerror",
"poolstats",
"workerstats",
"block",
"addrauth",
"heartbeat"
};
static const char *ckdb_seq_names[] = {
"seqauthorise",
"seqworkinfo",
"seqageworkinfo",
"seqshares",
"seqshareerror",
"seqpoolstats",
"seqworkerstats",
"seqblock",
"seqaddrauth",
"seqheartbeat"
};
#define ID_COUNT (sizeof(ckdb_ids)/sizeof(char *))
struct stratifier_data { struct stratifier_data {
ckpool_t *ckp; ckpool_t *ckp;
@ -361,8 +400,10 @@ struct stratifier_data {
mutex_t ckdb_lock; mutex_t ckdb_lock;
/* Protects sequence numbers */ /* Protects sequence numbers */
mutex_t ckdb_msg_lock; mutex_t ckdb_msg_lock;
/* Incrementing sequence number */ /* Incrementing global sequence number */
int ckdb_seq; int ckdb_seq;
/* Incrementing ckdb_ids[] sequence numbers */
int ckdb_seq_ids[ID_COUNT];
bool ckdb_offline; bool ckdb_offline;
bool verbose; bool verbose;
@ -438,30 +479,6 @@ struct json_entry {
#define GEN_NORMAL 1 #define GEN_NORMAL 1
#define GEN_PRIORITY 2 #define GEN_PRIORITY 2
#define ID_AUTH 0
#define ID_WORKINFO 1
#define ID_AGEWORKINFO 2
#define ID_SHARES 3
#define ID_SHAREERR 4
#define ID_POOLSTATS 5
#define ID_WORKERSTATS 6
#define ID_BLOCK 7
#define ID_ADDRAUTH 8
#define ID_HEARTBEAT 9
static const char *ckdb_ids[] = {
"authorise",
"workinfo",
"ageworkinfo",
"shares",
"shareerror",
"poolstats",
"workerstats",
"block",
"addrauth",
"heartbeat"
};
/* For storing a set of messages within another lock, allowing us to dump them /* For storing a set of messages within another lock, allowing us to dump them
* to the log outside of lock */ * to the log outside of lock */
static void add_msg_entry(char_entry_t **entries, char **buf) static void add_msg_entry(char_entry_t **entries, char **buf)
@ -668,7 +685,8 @@ static char *ckdb_msg(ckpool_t *ckp, sdata_t *sdata, json_t *val, const int idty
/* Set the atomically incrementing sequence number */ /* Set the atomically incrementing sequence number */
mutex_lock(&sdata->ckdb_msg_lock); mutex_lock(&sdata->ckdb_msg_lock);
json_set_int(val, "seq", sdata->ckdb_seq++); json_set_int(val, "seqall", sdata->ckdb_seq++);
json_set_int(val, ckdb_seq_names[idtype], sdata->ckdb_seq_ids[idtype]++);
mutex_unlock(&sdata->ckdb_msg_lock); mutex_unlock(&sdata->ckdb_msg_lock);
json_msg = json_dumps(val, JSON_COMPACT); json_msg = json_dumps(val, JSON_COMPACT);
@ -3792,14 +3810,20 @@ static int send_recv_auth(stratum_instance_t *client)
worker_instance_t *worker = client->worker_instance; worker_instance_t *worker = client->worker_instance;
json_error_t err_val; json_error_t err_val;
json_t *val = NULL; json_t *val = NULL;
int offset = 0;
LOGINFO("Got ckdb response: %s", buf); LOGINFO("Got ckdb response: %s", buf);
response = alloca(responselen); response = alloca(responselen);
memset(response, 0, responselen); memset(response, 0, responselen);
if (unlikely(sscanf(buf, "id.%*d.%s", response) < 1 || strlen(response) < 1 || !strchr(response, '='))) { if (unlikely(sscanf(buf, "id.%*d.%c%n", response, &offset) < 1)) {
LOGWARNING("Got1 unparseable ckdb auth response: %s", buf);
goto out_fail;
}
strcpy(response+1, buf+offset);
if (!strchr(response, '=')) {
if (cmdmatch(response, "failed")) if (cmdmatch(response, "failed"))
goto out; goto out;
LOGWARNING("Got unparseable ckdb auth response: %s", buf); LOGWARNING("Got2 unparseable ckdb auth response: %s", buf);
goto out_fail; goto out_fail;
} }
cmd = response; cmd = response;
@ -5221,9 +5245,11 @@ static void ckdbq_process(ckpool_t *ckp, char *msg)
responselen = strlen(buf); responselen = strlen(buf);
if (likely(responselen > 0)) { if (likely(responselen > 0)) {
char *response = alloca(responselen); char *response = alloca(responselen);
int offset = 0;
memset(response, 0, responselen); memset(response, 0, responselen);
sscanf(buf, "id.%*d.%s", response); if (sscanf(buf, "id.%*d.%c%n", response, &offset) > 0) {
strcpy(response+1, buf+offset);
if (safecmp(response, "ok")) { if (safecmp(response, "ok")) {
char *cmd; char *cmd;
@ -5235,7 +5261,9 @@ static void ckdbq_process(ckpool_t *ckp, char *msg)
parse_ckdb_cmd(ckp, cmd); parse_ckdb_cmd(ckp, cmd);
} }
} else } else
LOGWARNING("Got failed ckdb response: %s", buf); LOGWARNING("Got ckdb failure response: %s", buf);
} else
LOGWARNING("Got bad ckdb response: %s", buf);
free(buf); free(buf);
} }
} }

Loading…
Cancel
Save