From ccd6d1a38c4c75b0541926a8ed851a7014cf6f91 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Thu, 26 Feb 2026 16:19:17 +0100 Subject: [PATCH] Move db stats to separate classes for each db type Project......: Performance Profiling Sponsored-by.: NLnet NGI0 Commons Fund --- Zotlabs/Lib/DbStats.php | 43 +++++++++++++++++++++++++++++++++ Zotlabs/Lib/MySQLDbStats.php | 37 ++++++++++++++++++++++++++++ Zotlabs/Lib/PostgresDbStats.php | 32 ++++++++++++++++++++++++ Zotlabs/Module/Perfstats.php | 15 +++--------- tests/unit/Lib/DbStatsTest.php | 41 +++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 Zotlabs/Lib/DbStats.php create mode 100644 Zotlabs/Lib/MySQLDbStats.php create mode 100644 Zotlabs/Lib/PostgresDbStats.php create mode 100644 tests/unit/Lib/DbStatsTest.php diff --git a/Zotlabs/Lib/DbStats.php b/Zotlabs/Lib/DbStats.php new file mode 100644 index 000000000..83186966b --- /dev/null +++ b/Zotlabs/Lib/DbStats.php @@ -0,0 +1,43 @@ + + * + * SPDX-License-Identifier: MIT + */ + +namespace Zotlabs\Lib; + +use DBA; + +/** + * Abstract class to obtain statistics from the database. + * + * This class should not be instantiated on it's own, but you can get + * a concrete class for the configured database type of this site by + * calling the `DbStats::getStats()` function. + */ +abstract class DbStats { + + /** + * Get an object for getting statistics from the database. + * + * @return DbStats The concrete class for obtaining the statistics from + * this instances database. + */ + public static function getStats(): DbStats { + return DBA::$dba->is_postgres() + ? new PostgresDbStats() + : new MySQLDbStats(); + } + + /** + * Return the number of queries recorded by the database. + * + * @return int Number of queries. + */ + public abstract function getQueries(): int; + + // Prevent instantiation of this class + private function __construct() {} +} diff --git a/Zotlabs/Lib/MySQLDbStats.php b/Zotlabs/Lib/MySQLDbStats.php new file mode 100644 index 000000000..c7376e37f --- /dev/null +++ b/Zotlabs/Lib/MySQLDbStats.php @@ -0,0 +1,37 @@ + + * + * SPDX-License-Identifier: MIT + */ + +namespace Zotlabs\Lib; + +use DBA; +use PDO; + +/** + * Concrete implementation for getting stats from MySQL and MariaDB databases. + */ +class MySQLDbStats extends DbStats { + + public function getQueries(): int { + // + // We can't use the regular Hubzilla db helper function here, as + // it will only return information from a `SELECT` statement. + // + // Use the basic PDO access instead. + // + $query = DBA::$dba->db->prepare('SHOW STATUS LIKE "Queries"'); + $query->execute(); + + $result = $query->fetch(PDO::FETCH_ASSOC); + logger(print_r($result, true)); + if (!empty($result)) { + return $result['Value'] ?? -1; + } + + return 0; + } +} diff --git a/Zotlabs/Lib/PostgresDbStats.php b/Zotlabs/Lib/PostgresDbStats.php new file mode 100644 index 000000000..97dc4a6ec --- /dev/null +++ b/Zotlabs/Lib/PostgresDbStats.php @@ -0,0 +1,32 @@ + + * + * SPDX-License-Identifier: MIT + */ + +namespace Zotlabs\Lib; + +use DBA; + +/** + * Concrete implementation for getting stats from PostgreSQL databases. + */ +class PostgresDbStats extends DbStats { + + public function getQueries(): int { + $sqlGetQps = <<<'SQL' + select (xact_commit + xact_rollback) as queries + from pg_stat_database + where datname='%s' + SQL; + + $result = q($sqlGetQps, DBA::$dba->dbname); + if (!empty($result)) { + return $result[0]['queries'] ?? -1; + } + + return 0; + } +} diff --git a/Zotlabs/Module/Perfstats.php b/Zotlabs/Module/Perfstats.php index f5d6b9c8a..afc9adea4 100644 --- a/Zotlabs/Module/Perfstats.php +++ b/Zotlabs/Module/Perfstats.php @@ -10,6 +10,7 @@ namespace Zotlabs\Module; use DBA; +use Zotlabs\Lib\DbStats; use Zotlabs\Lib\Queue; use Zotlabs\Lib\QueueWorkerStats; use Zotlabs\Web\Controller; @@ -67,17 +68,7 @@ class Perfstats extends Controller } private function getNumQueries(): int { - static $sqlGetQps = <<<'SQL' - select sum(xact_commit + xact_rollback) as sum - from pg_stat_database - where datname='%s' - SQL; - - $result = q($sqlGetQps, DBA::$dba->dbname); - if (!empty($result)) { - return $result[0]['sum'] ?? -1; - } - - return 0; + $stats = DbStats::getStats(); + return $stats->getQueries(); } } diff --git a/tests/unit/Lib/DbStatsTest.php b/tests/unit/Lib/DbStatsTest.php new file mode 100644 index 000000000..beb522a46 --- /dev/null +++ b/tests/unit/Lib/DbStatsTest.php @@ -0,0 +1,41 @@ + + * + * SPDX-License-Identifier: MIT + */ + +namespace Zotlabs\Tests\Unit\Lib; + +use DBA; +use Zotlabs\Lib\DbStats; +use Zotlabs\Tests\Unit\UnitTestCase; + +class DbStatsTest extends UnitTestCase +{ + public function testGetQueries(): void { + $stats = DbStats::getStats(); + $this->assertNotNull($stats); + $this->assertInstanceOf(DbStats::class, $stats); + + $numQueries = $stats->getQueries(); + $this->assertNotEquals(0, $numQueries); + + if (!DBA::$dba->is_postgres()) { + // + // Postgres will only update the stats once the transaction + // is committed or rolled back. As we wrap the tests in a + // transaction to begin with, the stats won't change here, + // so we skip this test on Postgres. + // + dbq("select * from account"); + dbq("select * from channel"); + dbq("select * from xchan"); + + $numMoreQueries = $stats->getQueries(); + $this->assertGreaterThan($numQueries, $numMoreQueries); + } + } +}