[IMPROVED] Unified user speed statistics

* [ADDED] getUserMiningStats to fetch all speed related data
 * Uses global cache if available, falls back to local query and then
   local caches
* [REMOVED] getUserHashrate, getUserSharerate, getUserAvgShareDifficulty
* [UPDATED] All code occurences for the above to use the new system

Probably won't change much since global cache was already used but does
help on the Dashboard since we combine at least 2 calls into one.
This commit is contained in:
Sebastian Grewe 2014-02-26 09:27:32 +01:00
parent d82ff63006
commit 78619c1427
7 changed files with 38 additions and 95 deletions

View File

@ -489,47 +489,6 @@ class Statistics extends Base {
} }
} }
/**
* Fetch total user hashrate based on shares and archived shares
* @param $username string username
* @param $account_id int account id
* @return data integer Current Hashrate in khash/s
**/
public function getUserHashrate($username, $account_id=NULL, $interval=180) {
$this->debug->append("STA " . __METHOD__, 4);
// Dual-caching, try statistics cron first, then fallback to local, then fallbock to SQL
if ($this->getGetCache() && $data = $this->memcache->getStatic(STATISTICS_ALL_USER_HASHRATES)) {
if (array_key_exists($account_id, $data['data']))
return $data['data'][$account_id]['hashrate'];
// We have no cached value, we return defaults
return 0;
}
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
IFNULL(IF(our_result='Y', ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000), 0), 0) AS hashrate
FROM (
SELECT
id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty
FROM
shares
WHERE username LIKE ?
AND time > DATE_SUB(now(), INTERVAL ? SECOND)
AND our_result = 'Y'
UNION
SELECT
share_id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty
FROM
shares_archive
WHERE username LIKE ?
AND time > DATE_SUB(now(), INTERVAL ? SECOND)
AND our_result = 'Y') AS temp");
$username = $username . ".%";
if ($this->checkStmt($stmt) && $stmt->bind_param("isisi", $interval, $username, $interval, $username, $interval) && $stmt->execute() && $result = $stmt->get_result() )
return $this->memcache->setCache(__FUNCTION__ . $account_id, (float)$result->fetch_object()->hashrate);
return $this->sqlError();
}
public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_pps_id) { public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_pps_id) {
$this->debug->append("STA " . __METHOD__, 4); $this->debug->append("STA " . __METHOD__, 4);
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
@ -546,60 +505,32 @@ class Statistics extends Base {
return $this->sqlError(); return $this->sqlError();
} }
/**
* Get average share difficulty across all workers for user
* @param username string username
* @param $account_id int account id
* @param interval int Data interval in seconds
* @return double Share difficulty or 0
**/
public function getUserShareDifficulty($username, $account_id=NULL, $interval=180) {
$this->debug->append("STA " . __METHOD__, 4);
// Dual-caching, try statistics cron first, then fallback to local, then fallbock to SQL
if ($this->getGetCache() && $data = $this->memcache->getStatic(STATISTICS_ALL_USER_HASHRATES)) {
if (array_key_exists($account_id, $data['data']))
return $data['data'][$account_id]['avgsharediff'];
// We have no cached value, we return defaults
return 0;
}
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff,
COUNT(s.id) AS total
FROM " . $this->share->getTableName() . " AS s
WHERE username LIKE ?
AND time > DATE_SUB(now(), INTERVAL ? SECOND)
AND our_result = 'Y'
");
$username = $username . ".%";
if ($this->checkStmt($stmt) && $stmt->bind_param("si", $username, $interval) && $stmt->execute() && $result = $stmt->get_result() )
return $this->memcache->setCache(__FUNCTION__ . $account_id, (float)$result->fetch_object()->avgsharediff);
return $this->sqlError();
}
/** /**
* Get Shares per x interval by user * Get Shares per x interval by user
* @param username string username * @param username string username
* @param $account_id int account id * @param $account_id int account id
* @return data integer Current Sharerate in shares/s * @return data integer Current Sharerate in shares/s
**/ **/
public function getUserSharerate($username, $account_id=NULL, $interval=180) { public function getUserMiningStats($username, $account_id=NULL, $interval=180) {
$this->debug->append("STA " . __METHOD__, 4); $this->debug->append("STA " . __METHOD__, 4);
// Dual-caching, try statistics cron first, then fallback to local, then fallbock to SQL // Dual-caching, try statistics cron first, then fallback to local, then fallbock to SQL
if ($this->getGetCache() && $data = $this->memcache->getStatic(STATISTICS_ALL_USER_HASHRATES)) { if ($this->getGetCache() && $data = $this->memcache->getStatic(STATISTICS_ALL_USER_HASHRATES)) {
if (array_key_exists($account_id, $data['data'])) if (array_key_exists($account_id, $data['data'])) {
return $data['data'][$account_id]['sharerate']; $retData['hashrate'] = $data['data'][$account_id]['hashrate'];
// We have no cached value, we return defaults $retData['sharerate'] = $data['data'][$account_id]['sharerate'];
return 0; $retData['avgsharediff'] = $data['data'][$account_id]['avgsharediff'];
return $retData;
}
} }
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare(" $stmt = $this->mysqli->prepare("
SELECT SELECT
IFNULL(COUNT(*) / ?, 0) AS sharerate IFNULL(COUNT(*) / ?, 0) AS sharerate,
IFNULL(ROUND(SUM(difficulty) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000, 2), 0) AS hashrate,
IFNULL(AVG(difficulty), 0) AS avgsharediff
FROM ( FROM (
SELECT SELECT
id id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty
FROM FROM
shares shares
WHERE username LIKE ? WHERE username LIKE ?
@ -607,7 +538,7 @@ class Statistics extends Base {
AND our_result = 'Y' AND our_result = 'Y'
UNION UNION
SELECT SELECT
share_id share_id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty
FROM FROM
shares_archive shares_archive
WHERE username LIKE ? WHERE username LIKE ?
@ -615,8 +546,8 @@ class Statistics extends Base {
AND our_result = 'Y' AND our_result = 'Y'
) AS temp"); ) AS temp");
$username = $username . ".%"; $username = $username . ".%";
if ($this->checkStmt($stmt) && $stmt->bind_param("isisi", $interval, $username, $interval, $username, $interval) && $stmt->execute() && $result = $stmt->get_result() ) if ($this->checkStmt($stmt) && $stmt->bind_param("iisisi", $interval, $interval, $username, $interval, $username, $interval) && $stmt->execute() && $result = $stmt->get_result() )
return $this->memcache->setCache(__FUNCTION__ . $account_id, (float)$result->fetch_object()->sharerate); return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc());
return $this->sqlError(); return $this->sqlError();
} }

View File

@ -58,11 +58,12 @@ if (isset($_REQUEST['filter'])) {
$aBalance = $transaction->getBalance($aUser['id']); $aBalance = $transaction->getBalance($aUser['id']);
$aUser['balance'] = $aBalance['confirmed']; $aUser['balance'] = $aBalance['confirmed'];
$aUser['signup_timestamp'] = $user->getSignupTime($aUser['id']); $aUser['signup_timestamp'] = $user->getSignupTime($aUser['id']);
$aUser['hashrate'] = $statistics->getUserHashrate($aUser['username'], $aUser['id']); $aUserMiningStats = $statistics->getUserMiningStats($aUser['username'], $aUser['id']);
$aUser['hashrate'] = $aUserMiningStats['hashrate'];
if ($config['payout_system'] == 'pps') { if ($config['payout_system'] == 'pps') {
$aUser['sharerate'] = $statistics->getUserSharerate($aUser['username'], $aUser['id']); $aUser['sharerate'] = $aUserMiningStats['sharerate'];
$aUser['difficulty'] = $statistics->getUserShareDifficulty($aUser['username'], $aUser['id']); $aUser['difficulty'] = $aUserMiningStats['avgsharediff'];
$aUser['estimates'] = $statistics->getUserEstimates($aUser['sharerate'], $aUser['difficulty'], $user->getUserDonatePercent($aUser['id']), $user->getUserNoFee($aUser['id']), $statistics->getPPSValue()); $aUser['estimates'] = $statistics->getUserEstimates($aUser['sharerate'], $aUser['difficulty'], $user->getUserDonatePercent($aUser['id']), $user->getUserNoFee($aUser['id']), $statistics->getPPSValue());
} else { } else {
$aUser['estimates'] = $statistics->getUserEstimates($aRoundShares, $aUser['shares'], $aUser['donate_percent'], $aUser['no_fees']); $aUser['estimates'] = $statistics->getUserEstimates($aRoundShares, $aUser['shares'], $aUser['donate_percent'], $aUser['no_fees']);

View File

@ -43,9 +43,10 @@ if ( ! $dNetworkHashrateModifier = $setting->getValue('statistics_network_hashra
$statistics->setGetCache(false); $statistics->setGetCache(false);
$dPoolHashrate = $statistics->getCurrentHashrate($interval); $dPoolHashrate = $statistics->getCurrentHashrate($interval);
if ($dPoolHashrate > $dNetworkHashrate) $dNetworkHashrate = $dPoolHashrate; if ($dPoolHashrate > $dNetworkHashrate) $dNetworkHashrate = $dPoolHashrate;
$dPersonalHashrate = $statistics->getUserHashrate($username, $user_id, $interval); $aUserMiningStats = $statistics->getUserMiningStats($username, $user_id, $interval);
$dPersonalSharerate = $statistics->getUserSharerate($username, $user_id, $interval); $dPersonalHashrate = $aUserMiningStats['hashrate'];
$dPersonalShareDifficulty = $statistics->getUserShareDifficulty($username, $user_id, $interval); $dPersonalSharerate = $aUserMiningStats['sharerate'];
$dPersonalShareDifficulty = $aUserMiningStats['avgsharediff'];
$statistics->setGetCache(true); $statistics->setGetCache(true);
// Use caches for this one // Use caches for this one

View File

@ -13,7 +13,8 @@ if ( ! $interval = $setting->getValue('statistics_ajax_data_interval')) $interva
// Gather un-cached data // Gather un-cached data
$statistics->setGetCache(false); $statistics->setGetCache(false);
$hashrate = $statistics->getUserHashrate($username, $user_id, $interval); $aUserMiningStats = $statistics->getUserMiningStats($username, $user_id, $interval);
$hashrate = $aUserMiningStats['hashrate'];
$statistics->setGetCache(true); $statistics->setGetCache(true);
// Output JSON // Output JSON

View File

@ -13,7 +13,8 @@ if ( ! $interval = $setting->getValue('statistics_ajax_data_interval')) $interva
// Gather un-cached data // Gather un-cached data
$statistics->setGetCache(false); $statistics->setGetCache(false);
$sharerate = $statistics->getUserSharerate($username, $user_id, $interval); $aUserMiningStats = $statistics->getUserMiningStats($username, $user_id, $interval);
$sharerate = $aUserMiningStats['sharerate'];
$statistics->setGetCache(true); $statistics->setGetCache(true);
// Output JSON format // Output JSON format

View File

@ -7,15 +7,22 @@ $api->isActive();
// Check user token // Check user token
$user_id = $api->checkAccess($user->checkApiKey($_REQUEST['api_key']), @$_REQUEST['id']); $user_id = $api->checkAccess($user->checkApiKey($_REQUEST['api_key']), @$_REQUEST['id']);
$username = $user->getUsername($user_id); $username = $user->getUsername($user_id);
// Fetch some settings
if ( ! $interval = $setting->getValue('statistics_ajax_data_interval')) $interval = 300;
// Fetch transaction summary // Fetch transaction summary
$aTransactionSummary = $transaction->getTransactionSummary($user_id); $aTransactionSummary = $transaction->getTransactionSummary($user_id);
// User mining status
$aUserMiningStats = $statistics->getUserMiningStats($username, $user_id, $interval);
// Output JSON format // Output JSON format
$data = array( $data = array(
'username' => $username, 'username' => $username,
'shares' => $statistics->getUserShares($username, $user_id), 'shares' => $statistics->getUserShares($username, $user_id),
'hashrate' => $statistics->getUserHashrate($username, $user_id), 'hashrate' => $aUserMiningStats['hashrate'],
'sharerate' => $statistics->getUserSharerate($username, $user_id) 'sharerate' => $aUserMiningStats['sharerate']
); );
echo $api->get_json($data); echo $api->get_json($data);

View File

@ -133,9 +133,10 @@ if (@$_SESSION['USERDATA']['id']) {
// Other userdata that we can cache savely // Other userdata that we can cache savely
$aGlobal['userdata']['shares'] = $statistics->getUserShares($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); $aGlobal['userdata']['shares'] = $statistics->getUserShares($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']);
$aGlobal['userdata']['rawhashrate'] = $statistics->getUserHashrate($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); $aUserMiningStats = $statistics->getUserMiningStats($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']);
$aGlobal['userdata']['rawhashrate'] = $aUserMiningStats['hashrate'];
$aGlobal['userdata']['hashrate'] = $aGlobal['userdata']['rawhashrate'] * $dPersonalHashrateModifier; $aGlobal['userdata']['hashrate'] = $aGlobal['userdata']['rawhashrate'] * $dPersonalHashrateModifier;
$aGlobal['userdata']['sharerate'] = $statistics->getUserSharerate($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); $aGlobal['userdata']['sharerate'] = $aUserMiningStats['sharerate'];
switch ($config['payout_system']) { switch ($config['payout_system']) {
case 'prop': case 'prop':