optimize ocelot drain check query

This commit is contained in:
Spine
2025-06-26 19:49:11 +00:00
parent c78e2712a6
commit acdb0a0d16
9 changed files with 69 additions and 20 deletions

View File

@@ -186,8 +186,9 @@ class DB extends Base {
SELECT count(*)
FROM performance_schema.processlist
WHERE COMMAND NOT IN ('Sleep')
AND TIME > 1200;
");
AND TIME > ?
", MYSQL_SLOW_QUERY_TIMEOUT
);
}
public static function lookupDirection(string $direction): Direction {

View File

@@ -87,6 +87,17 @@ class MysqlTable extends AbstractTable {
);
}
public function recentUpdate(int $seconds): bool {
return (bool)self::$db->scalar("
SELECT 1
FROM information_schema.tables
WHERE table_schema = ?
AND table_name = ?
AND update_time > now() - INTERVAL ? SECOND
", MYSQL_DB, $this->name, $seconds
);
}
public function stats(): array {
return self::$db->rowAssoc("
SELECT t.TABLE_ROWS,

View File

@@ -341,4 +341,14 @@ class Tracker extends Base {
");
return self::$db->to_array(false, MYSQLI_ASSOC);
}
public function recentUpdate(int $seconds): bool {
return (bool)self::$db->scalar("
SELECT 1
FROM xbt_files_users
WHERE mtime > unix_timestamp(now() - INTERVAL ? SECOND)
LIMIT 1
", $seconds
);
}
}

View File

@@ -75,22 +75,6 @@ class Activity extends \Gazelle\BaseUser {
return $this;
}
public function setDb(\Gazelle\DB $dbMan): static {
if ($this->user->permitted('admin_site_debug')) {
$longRunning = $dbMan->longRunning();
if ($longRunning > 0) {
$message = "$longRunning long-running DB operation" . plural($longRunning);
$this->setAlert("<span title=\"$message\" class=\"sys-error\">DB</span>");
}
// If Ocelot can no longer write to xbt_files_users, it will drain after an hour
// Look for database locks and check the Ocelot log
if (!self::$db->scalar('SELECT fid FROM xbt_files_users LIMIT 1')) {
$this->setAlert('<span style="color: red">Ocelot not updating!</span>');
}
}
return $this;
}
public function setPayment(\Gazelle\Manager\Payment $payMan): static {
if ($this->user->permitted('admin_manage_payments')) {
$soon = $payMan->soon();

View File

@@ -48,7 +48,6 @@ class View extends Base {
->setReport(new Stats\Report())
->setPayment($payMan)
->setApplicant(new Manager\Applicant())
->setDb(new DB())
->setScheduler(new TaskScheduler())
->setSSLHost(new Manager\SSLHost())
->setAutoReport(
@@ -58,6 +57,23 @@ class View extends Base {
)
);
if ($user->permitted('admin_site_debug')) {
$longRunning = new DB()->longRunning();
if ($longRunning > 0) {
$message = "$longRunning long-running DB operation" . plural($longRunning);
$activity->setAlert("<span title=\"$message\" class=\"sys-error\">DB</span>");
}
// Check that Ocelot is still writing to xbt_files_users.
// If not, look for database locks and check the Ocelot log
if (!new Tracker()->recentUpdate(TRACKER_REFRESH_TIMEOUT)) {
$activity->setAlert('<span title="No update received from tracker within '
. Util\Time::convertSeconds(TRACKER_REFRESH_TIMEOUT)
. '" class="sys-error">TRACKER</span>'
);
}
}
$threshold = new Manager\SiteOption()
->findValueByName('download-warning-threshold');
if ($threshold) {

View File

@@ -194,6 +194,9 @@ defined('MYSQL_RO_USER') or define('MYSQL_RO_USER', 'gazro');
// The password of the above account.
defined('MYSQL_RO_PASS') or define('MYSQL_RO_PASS', 'passro');
// Warn if there is a query that has been running for too long
defined('MYSQL_SLOW_QUERY_TIMEOUT') or define('MYSQL_SLOW_QUERY_TIMEOUT', 1200);
// The username of the Phinx account (used for schema modifications).
// In production, this account will have a different set of grants compared
// to the website account (so that if the website account is compromised, it
@@ -292,6 +295,12 @@ defined('TRACKER_NAME') or define('TRACKER_NAME', '127.0.0.1' . ":" . TRACKER_PO
// be exactly 32 alphanumeric characters.
defined('TRACKER_SECRET') or define('TRACKER_SECRET', '00000000000000000000000000000000');
// How long to wait in the absense of an update from the tracker to warn of a
// problem? Busy with millions of peears receive multiple updates per second.
// Sites with a few thousand peers or less may not see an update for several
// seconds.
defined('TRACKER_REFRESH_TIMEOUT') or define('TRACKER_REFRESH_TIMEOUT', 5);
// Second shared secret that is compiled into Ocelot (see config.cpp). Must
// be exactly 32 alphanumeric characters.
defined('TRACKER_REPORTKEY') or define('TRACKER_REPORTKEY', '00000000000000000000000000000000');

View File

@@ -363,6 +363,8 @@ class DbTest extends TestCase {
),
'mysql-fkey-list'
);
// not a problem that the table does not exist, the SQL is being tested
$this->assertFalse($bad->recentUpdate(600), 'mysql-table-recent-update');
}
public function testPgTable(): void {

View File

@@ -182,4 +182,21 @@ class TrackerTest extends TestCase {
$this->assertEquals(1, $tracker->expireFreeleechTokens("$userId:$torrentId,$userId:$fakeId"), 'tracker-expire-tokens');
$downloader->remove();
}
public function testTrackerUpdate(): void {
$this->user = Helper::makeUser('trkfree.' . randomString(10), 'tracker');
$this->user->requestContext()->setViewer($this->user);
$this->torrent = Helper::makeTorrentMusic(
Helper::makeTGroupMusic(
name: 'tracker ' . randomString(10),
artistName: [[ARTIST_MAIN], ['Tracker Girl ' . randomString(12)]],
tagName: ['trap'],
user: $this->user,
),
user: $this->user,
title: 'tracker ' . randomString(10),
);
Helper::generateTorrentSeed($this->torrent, $this->user);
$this->assertTrue(new Tracker()->recentUpdate(60), 'tracker-recent-update');
}
}

View File

@@ -30,7 +30,6 @@ class UserActivityTest extends TestCase {
$this->assertInstanceOf(User\Activity::class, $activity->configure(), 'user-activity-configure');
$this->assertInstanceOf(User\Activity::class, $activity->setApplicant(new Manager\Applicant()), 'user-activity-applicant');
$this->assertInstanceOf(User\Activity::class, $activity->setDb(new DB()), 'user-activity-db');
$this->assertInstanceOf(User\Activity::class, $activity->setPayment(new Manager\Payment()), 'user-activity-payment');
$this->assertInstanceOf(User\Activity::class, $activity->setReferral(new Manager\Referral()), 'user-activity-referral');
$this->assertInstanceOf(User\Activity::class, $activity->setReport(new Stats\Report()), 'user-activity-report');