From 1d560d9acaf42bffcac7231ea004b668536dd251 Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Wed, 12 Jul 2023 03:17:19 +0800 Subject: [PATCH] add seed_points_per_hour + improve calculateUserSeedBonus --- app/Jobs/CalculateUserSeedBonus.php | 70 +------------- app/Models/User.php | 4 +- app/Repositories/CleanupRepository.php | 95 +++++++++++++++++-- ...dd_seed_points_per_hour_to_users_table.php | 32 +++++++ include/cleanup.php | 28 ++---- include/constants.php | 2 +- include/functions.php | 28 ++++-- 7 files changed, 148 insertions(+), 111 deletions(-) create mode 100644 database/migrations/2023_07_12_014056_add_seed_points_per_hour_to_users_table.php diff --git a/app/Jobs/CalculateUserSeedBonus.php b/app/Jobs/CalculateUserSeedBonus.php index ff819862..4136c069 100644 --- a/app/Jobs/CalculateUserSeedBonus.php +++ b/app/Jobs/CalculateUserSeedBonus.php @@ -4,6 +4,7 @@ namespace App\Jobs; use App\Models\Setting; use App\Models\User; +use App\Repositories\CleanupRepository; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; @@ -55,74 +56,7 @@ class CalculateUserSeedBonus implements ShouldQueue */ public function handle() { - $beginTimestamp = time(); - $logPrefix = sprintf("[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_JOB], commonRequestId: %s, beginUid: %s, endUid: %s", $this->requestId, $this->beginUid, $this->endUid); - $sql = sprintf("select userid from peers where userid > %s and userid <= %s and seeder = 'yes' group by userid", $this->beginUid, $this->endUid); - $results = NexusDB::select($sql); - $count = count($results); - do_log("$logPrefix, [GET_UID], sql: $sql, count: " . count($results)); - if ($count == 0) { - do_log("$logPrefix, no user..."); - return; - } - $haremAdditionFactor = Setting::get('bonus.harem_addition'); - $officialAdditionFactor = Setting::get('bonus.official_addition'); - $donortimes_bonus = Setting::get('bonus.donortimes'); - $autoclean_interval_one = Setting::get('main.autoclean_interval_one'); - $sql = sprintf("select %s from users where id in (%s)", implode(',', User::$commonFields), implode(',', array_column($results, 'userid'))); - $results = NexusDB::select($sql); - $logFile = getLogFile("seed-bonus-points"); - do_log("$logPrefix, [GET_UID_REAL], count: " . count($results) . ", logFile: $logFile"); - $fd = fopen($logFile, 'a'); - foreach ($results as $userInfo) - { - $uid = $userInfo['id']; - $isDonor = is_donor($userInfo); - $seedBonusResult = calculate_seed_bonus($uid); - $bonusLog = "[CLEANUP_CLI_CALCULATE_SEED_BONUS_HANDLE_USER], user: $uid, seedBonusResult: " . nexus_json_encode($seedBonusResult); - $all_bonus = $seedBonusResult['seed_bonus']; - $bonusLog .= ", all_bonus: $all_bonus"; - if ($isDonor) { - $all_bonus = $all_bonus * $donortimes_bonus; - $bonusLog .= ", isDonor, donortimes_bonus: $donortimes_bonus, all_bonus: $all_bonus"; - } - if ($officialAdditionFactor > 0) { - $officialAddition = $seedBonusResult['official_bonus'] * $officialAdditionFactor; - $all_bonus += $officialAddition; - $bonusLog .= ", officialAdditionFactor: $officialAdditionFactor, official_bonus: {$seedBonusResult['official_bonus']}, officialAddition: $officialAddition, all_bonus: $all_bonus"; - } - if ($haremAdditionFactor > 0) { - $haremBonus = calculate_harem_addition($uid); - $haremAddition = $haremBonus * $haremAdditionFactor; - $all_bonus += $haremAddition; - $bonusLog .= ", haremAdditionFactor: $haremAdditionFactor, haremBonus: $haremBonus, haremAddition: $haremAddition, all_bonus: $all_bonus"; - } - if ($seedBonusResult['medal_additional_factor'] > 0) { - $medalAddition = $seedBonusResult['medal_bonus'] * $seedBonusResult['medal_additional_factor']; - $all_bonus += $medalAddition; - $bonusLog .= ", medalAdditionFactor: {$seedBonusResult['medal_additional_factor']}, medalBonus: {$seedBonusResult['medal_bonus']}, medalAddition: $medalAddition, all_bonus: $all_bonus"; - } - $dividend = 3600 / $autoclean_interval_one; - $all_bonus = $all_bonus / $dividend; - $seed_points = $seedBonusResult['seed_points'] / $dividend; - $updatedAt = now()->toDateTimeString(); - $sql = "update users set seed_points = ifnull(seed_points, 0) + $seed_points, seedbonus = seedbonus + $all_bonus, seed_points_updated_at = '$updatedAt' where id = $uid limit 1"; - do_log("$bonusLog, query: $sql"); - NexusDB::statement($sql); - if ($fd) { - $log = sprintf( - '%s|%s|%s|%s|%s|%s|%s|%s', - date('Y-m-d H:i:s'), $uid, - $userInfo['seed_points'], number_format($seed_points, 1, '.', ''), number_format($userInfo['seed_points'] + $seed_points, 1, '.', ''), - $userInfo['seedbonus'], number_format($all_bonus, 1, '.', ''), number_format($userInfo['seedbonus'] + $all_bonus, 1, '.', '') - ); - fwrite($fd, $log . PHP_EOL); - } else { - do_log("logFile: $logFile is not writeable!", 'error'); - } - } - $costTime = time() - $beginTimestamp; - do_log("$logPrefix, [DONE], cost time: $costTime seconds"); + CleanupRepository::runBatchJob(CleanupRepository::USER_SEED_BONUS_BATCH_KEY, $this->requestId); } /** diff --git a/app/Models/User.php b/app/Models/User.php index 2df762c8..0fd3c0c2 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -179,7 +179,7 @@ class User extends Authenticatable implements FilamentUser, HasName protected $fillable = [ 'username', 'email', 'passhash', 'secret', 'stylesheet', 'editsecret', 'added', 'modcomment', 'enabled', 'status', 'leechwarn', 'leechwarnuntil', 'page', 'class', 'uploaded', 'downloaded', 'clientselect', 'showclienterror', 'last_home', - 'seedbonus', 'bonuscomment', 'downloadpos', 'vip_added', 'vip_until', 'title', 'invites', 'attendance_card', + 'seedbonus', 'bonuscomment', 'downloadpos', 'vip_added', 'vip_until', 'title', 'invites', 'attendance_card', 'seed_points_per_hour' ]; /** @@ -223,6 +223,8 @@ class User extends Authenticatable implements FilamentUser, HasName 'uploaded', 'downloaded', 'seedbonus', 'seedtime', 'leechtime', 'invited_by', 'enabled', 'seed_points', 'last_access', 'invites', 'lang', 'attendance_card', 'privacy', 'noad', 'downloadpos', 'donoruntil', 'donor', + 'seedbonus', 'bonuscomment', 'downloadpos', 'vip_added', 'vip_until', 'title', 'invites', 'attendance_card', + 'seed_points_per_hour' ]; public static function getDefaultUserAttributes(): array diff --git a/app/Repositories/CleanupRepository.php b/app/Repositories/CleanupRepository.php index 9ba411da..957ef89e 100644 --- a/app/Repositories/CleanupRepository.php +++ b/app/Repositories/CleanupRepository.php @@ -1,6 +1,7 @@ eval(self::getAddRecordLuaScript(), $args, 2); + $result = $redis->eval(self::getAddRecordLuaScript(), $args, 3); $err = $redis->getLastError(); if ($err) { do_log("[REDIS_LUA_ERROR]: $err", "error"); @@ -40,6 +41,7 @@ class CleanupRepository extends BaseRepository $count = match ($batchKey) { self::USER_SEEDING_LEECHING_TIME_BATCH_KEY => self::updateUserLeechingSeedingTime($redis, $batch, $logPrefix), self::TORRENT_SEEDERS_ETC_BATCH_KEY => self::updateTorrentSeedersEtc($redis, $batch, $logPrefix), + self::USER_SEED_BONUS_BATCH_KEY => self::calculateUserSeedBonus($redis, $batch, $logPrefix), default => throw new \InvalidArgumentException("Invalid batchKey: $batchKey") }; //remove this batch @@ -138,29 +140,33 @@ class CleanupRepository extends BaseRepository } /** - * USER_SEEDING_LEECHING_TIME, TORRENT_SEEDERS_ETC, uid, torrentId, timeStr + * USER_SEED_BONUS, USER_SEEDING_LEECHING_TIME, TORRENT_SEEDERS_ETC, uid, uid, torrentId, timeStr * * @return string */ private static function getAddRecordLuaScript(): string { return <<<'LUA' -local batchList = {KEYS[1], KEYS[2]} +local batchList = {KEYS[1], KEYS[2], KEYS[3]} for k, v in pairs(batchList) do local batchKey = redis.call("GET", v) local isBatchKeyNew = false if batchKey == false then - batchKey = v .. ":" .. ARGV[3] + batchKey = v .. ":" .. ARGV[4] redis.call("SET", v, batchKey, "EX", 2592000) isBatchKeyNew = true end local hashKey - if k == 1 then + if (k == 1) + then hashKey = ARGV[1] - else + elseif (k == 2) + then hashKey = ARGV[2] + else + hashKey = ARGV[3] end - redis.call("HSETNX", batchKey, hashKey, ARGV[3]) + redis.call("HSETNX", batchKey, hashKey, ARGV[4]) if isBatchKeyNew then redis.call("EXPIRE", batchKey, 2592000) end @@ -173,4 +179,75 @@ LUA; return date('Ymd_His'); } + private static function calculateUserSeedBonus(\Redis $redis, $batch, $logPrefix) + { + $haremAdditionFactor = Setting::get('bonus.harem_addition'); + $officialAdditionFactor = Setting::get('bonus.official_addition'); + $donortimes_bonus = Setting::get('bonus.donortimes'); + $autoclean_interval_one = Setting::get('main.autoclean_interval_one'); + + $logFile = getLogFile("seed-bonus-points"); + do_log("$logPrefix, logFile: $logFile"); + $fd = fopen($logFile, 'a'); + + $count = 0; + $size = 1000; + $it = NULL; + /* Don't ever return an empty array until we're done iterating */ + $redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); + while($arr_keys = $redis->hScan($batch, $it, "*", $size)) { + foreach($arr_keys as $uid => $timestamp) { + do_log("$logPrefix $uid => $timestamp"); /* Print the hash member and value */ + + $userInfo = get_user_row($uid); + $isDonor = is_donor($userInfo); + $seedBonusResult = calculate_seed_bonus($uid); + $bonusLog = "[CLEANUP_CLI_CALCULATE_SEED_BONUS], user: $uid, seedBonusResult: " . nexus_json_encode($seedBonusResult); + $all_bonus = $seedBonusResult['seed_bonus']; + $bonusLog .= ", all_bonus: $all_bonus"; + if ($isDonor) { + $all_bonus = $all_bonus * $donortimes_bonus; + $bonusLog .= ", isDonor, donortimes_bonus: $donortimes_bonus, all_bonus: $all_bonus"; + } + if ($officialAdditionFactor > 0) { + $officialAddition = $seedBonusResult['official_bonus'] * $officialAdditionFactor; + $all_bonus += $officialAddition; + $bonusLog .= ", officialAdditionFactor: $officialAdditionFactor, official_bonus: {$seedBonusResult['official_bonus']}, officialAddition: $officialAddition, all_bonus: $all_bonus"; + } + if ($haremAdditionFactor > 0) { + $haremBonus = calculate_harem_addition($uid); + $haremAddition = $haremBonus * $haremAdditionFactor; + $all_bonus += $haremAddition; + $bonusLog .= ", haremAdditionFactor: $haremAdditionFactor, haremBonus: $haremBonus, haremAddition: $haremAddition, all_bonus: $all_bonus"; + } + if ($seedBonusResult['medal_additional_factor'] > 0) { + $medalAddition = $seedBonusResult['medal_bonus'] * $seedBonusResult['medal_additional_factor']; + $all_bonus += $medalAddition; + $bonusLog .= ", medalAdditionFactor: {$seedBonusResult['medal_additional_factor']}, medalBonus: {$seedBonusResult['medal_bonus']}, medalAddition: $medalAddition, all_bonus: $all_bonus"; + } + $dividend = 3600 / $autoclean_interval_one; + $all_bonus = $all_bonus / $dividend; + $seed_points = $seedBonusResult['seed_points'] / $dividend; + $updatedAt = now()->toDateTimeString(); + $sql = "update users set seed_points = ifnull(seed_points, 0) + $seed_points, seedbonus = seedbonus + $all_bonus, seed_points_per_hour = {$seedBonusResult['seed_points']} ,seed_points_updated_at = '$updatedAt' where id = $uid limit 1"; + do_log("$bonusLog, query: $sql"); + NexusDB::statement($sql); + if ($fd) { + $log = sprintf( + '%s|%s|%s|%s|%s|%s|%s|%s', + date('Y-m-d H:i:s'), $uid, + $userInfo['seed_points'], number_format($seed_points, 1, '.', ''), number_format($userInfo['seed_points'] + $seed_points, 1, '.', ''), + $userInfo['seedbonus'], number_format($all_bonus, 1, '.', ''), number_format($userInfo['seedbonus'] + $all_bonus, 1, '.', '') + ); + fwrite($fd, $log . PHP_EOL); + } else { + do_log("logFile: $logFile is not writeable!", 'error'); + } + $count++; + } + sleep(rand(1, 10)); + } + return $count; + } + } diff --git a/database/migrations/2023_07_12_014056_add_seed_points_per_hour_to_users_table.php b/database/migrations/2023_07_12_014056_add_seed_points_per_hour_to_users_table.php new file mode 100644 index 00000000..db3e7433 --- /dev/null +++ b/database/migrations/2023_07_12_014056_add_seed_points_per_hour_to_users_table.php @@ -0,0 +1,32 @@ +decimal('seed_points_per_hour',20, 1)->after("seed_points")->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn("seed_points_per_hour"); + }); + } +}; diff --git a/include/cleanup.php b/include/cleanup.php index 40f7a7af..496a9e71 100644 --- a/include/cleanup.php +++ b/include/cleanup.php @@ -300,28 +300,12 @@ function docleanup($forceAll = 0, $printProgress = false) { // } //chunk async - $asyncTaskCount = 3; - $baseDuration = floor($autoclean_interval_one / ($asyncTaskCount + 1)); - $delayBase = 0; - $requestId = nexus()->getRequestId(); - $maxUidRes = mysql_fetch_assoc(sql_query("select max(id) as max_uid from users limit 1")); - $maxUid = $maxUidRes['max_uid']; - $chunk = 1000; - $beginUid = 0; - $chunkCounts = ceil($maxUid / $chunk); - $delay = ceil($baseDuration/$chunkCounts); - $i = 0; - do_log("autoclean_interval_one: $autoclean_interval_one, baseDuration: $baseDuration, maxUid: $maxUid, chunk: $chunk, chunkCounts: $chunkCounts, delayBase: $delayBase, delay: $delay"); - do { - $command = sprintf( - 'cleanup --action=seed_bonus --begin_id=%s --end_id=%s --request_id=%s --delay=%s', - $beginUid, $beginUid + $chunk, $requestId, $delayBase + $i * $delay - ); - $output = executeCommand($command, 'string', true); - do_log(sprintf('command: %s, output: %s', $command, $output)); - $beginUid += $chunk; - $i++; - } while ($beginUid < $maxUid); + $command = sprintf( + 'cleanup --action=seed_bonus --begin_id=%s --end_id=%s --request_id=%s --delay=%s', + 0, 0, nexus()->getRequestId(), 0 + ); + $output = executeCommand($command, 'string', true); + do_log(sprintf('command: %s, output: %s', $command, $output)); $log = 'calculate seeding bonus'; do_log($log); diff --git a/include/constants.php b/include/constants.php index aaee0e16..a975f47e 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ where('invited_by', $uid) +// $harems = \App\Models\User::query() +// ->where('invited_by', $uid) +// ->where('status', \App\Models\User::STATUS_CONFIRMED) +// ->where('enabled', \App\Models\User::ENABLED_YES) +// ->get(['id']); +// $addition = 0; +// $haremsCount = $harems->count(); +// foreach ($harems as $harem) { +// $result = calculate_seed_bonus($harem->id); +// $addition += $result['seed_points']; +// } +// do_log("[HAREM_ADDITION], user: $uid, haremsCount: $haremsCount ,addition: $addition"); + + $addition = \Nexus\Database\NexusDB::table("users") + ->where("invited_by", $uid) ->where('status', \App\Models\User::STATUS_CONFIRMED) ->where('enabled', \App\Models\User::ENABLED_YES) - ->get(['id']); - $addition = 0; - $haremsCount = $harems->count(); - foreach ($harems as $harem) { - $result = calculate_seed_bonus($harem->id); - $addition += $result['seed_points']; - } - do_log("[HAREM_ADDITION], user: $uid, haremsCount: $haremsCount ,addition: $addition"); + ->sum("seed_points_per_hour") + ; + do_log("[HAREM_ADDITION], user: $uid, addition: $addition"); return $addition; }