diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3519835579..a4a0c35547 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6030,24 +6030,6 @@ parameters: count: 1 path: src/Encoding.php - - - message: '#^Binary operation "\*" between mixed and 100 results in an error\.$#' - identifier: binaryOp.invalid - count: 2 - path: src/Engines/Innodb.php - - - - message: '#^Binary operation "\*" between mixed and mixed results in an error\.$#' - identifier: binaryOp.invalid - count: 1 - path: src/Engines/Innodb.php - - - - message: '#^Binary operation "/" between \(float\|int\) and mixed results in an error\.$#' - identifier: binaryOp.invalid - count: 2 - path: src/Engines/Innodb.php - - message: ''' #^Call to deprecated method getInstance\(\) of class PhpMyAdmin\\Dbal\\DatabaseInterface\: @@ -6057,18 +6039,6 @@ parameters: count: 5 path: src/Engines/Innodb.php - - - message: '#^Loose comparison via "\=\=" is not allowed\.$#' - identifier: equal.notAllowed - count: 2 - path: src/Engines/Innodb.php - - - - message: '#^Parameter \#1 \$value of static method PhpMyAdmin\\Util\:\:formatNumber\(\) expects float\|int\|numeric\-string, mixed given\.$#' - identifier: argument.type - count: 11 - path: src/Engines/Innodb.php - - message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#' identifier: foreach.nonIterable diff --git a/psalm-baseline.xml b/psalm-baseline.xml index e7c301345b..ecd6ce9a2b 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -4096,29 +4096,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Engines/Innodb.php b/src/Engines/Innodb.php index 46675a633b..ac9f5e3cb3 100644 --- a/src/Engines/Innodb.php +++ b/src/Engines/Innodb.php @@ -1,13 +1,11 @@ fetchResult($sql, 0, 1); + $status = $this->getBufferPoolStatus(); - /** @var string[] $bytes */ - $bytes = Util::formatByteDown($status['Innodb_buffer_pool_pages_total'] * $status['Innodb_page_size']); + $bytes = Util::formatByteDown($status->pagesTotal * $status->innodbPageSize); $output = '' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n"; - // not present at least since MySQL 5.1.40 - if (isset($status['Innodb_buffer_pool_pages_latched'])) { + if ($status->pagesLatched !== null) { $output .= ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n"; } @@ -190,55 +180,41 @@ class Innodb extends StorageEngine . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ' . "\n" @@ -313,4 +289,14 @@ class Innodb extends StorageEngine return $dbi->fetchValue("SHOW GLOBAL VARIABLES LIKE 'innodb_file_per_table';", 1) === 'ON'; } + + private function getBufferPoolStatus(): BufferPool + { + $result = DatabaseInterface::getInstance()->tryQuery( + "SHOW STATUS WHERE Variable_name LIKE 'Innodb\\_buffer\\_pool\\_%' OR Variable_name = 'Innodb_page_size';", + cacheAffectedRows: false, + ); + + return BufferPool::fromResult($result !== false ? $result->fetchAllKeyPair() : []); + } } diff --git a/src/Engines/Innodb/BufferPool.php b/src/Engines/Innodb/BufferPool.php new file mode 100644 index 0000000000..2968f52629 --- /dev/null +++ b/src/Engines/Innodb/BufferPool.php @@ -0,0 +1,69 @@ + $result */ + public static function fromResult(array $result): self + { + return new self( + self::getNumeric($result['Innodb_page_size'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_pages_data'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_pages_dirty'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_pages_flushed'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_pages_free'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_pages_misc'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_pages_total'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_read_requests'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_reads'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_wait_free'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_write_requests'] ?? null) ?? '0', + self::getNumeric($result['Innodb_buffer_pool_pages_latched'] ?? null), + ); + } + + /** @return numeric-string|null */ + private static function getNumeric(string|null $value): string|null + { + return is_numeric($value) ? $value : null; + } +} diff --git a/tests/unit/Engines/Innodb/BufferPoolTest.php b/tests/unit/Engines/Innodb/BufferPoolTest.php new file mode 100644 index 0000000000..6a3f9388eb --- /dev/null +++ b/tests/unit/Engines/Innodb/BufferPoolTest.php @@ -0,0 +1,116 @@ + $result + * @param numeric-string $innodbPageSize + * @param numeric-string $pagesData + * @param numeric-string $pagesDirty + * @param numeric-string $pagesFlushed + * @param numeric-string $pagesFree + * @param numeric-string $pagesMisc + * @param numeric-string $pagesTotal + * @param numeric-string $readRequests + * @param numeric-string $reads + * @param numeric-string $waitFree + * @param numeric-string $writeRequests + * @param numeric-string|null $pagesLatched + */ + #[DataProvider('resultProvider')] + public function testCreateFromResult( + array $result, + string $innodbPageSize, + string $pagesData, + string $pagesDirty, + string $pagesFlushed, + string $pagesFree, + string $pagesMisc, + string $pagesTotal, + string $readRequests, + string $reads, + string $waitFree, + string $writeRequests, + string|null $pagesLatched, + ): void { + $bufferPool = BufferPool::fromResult($result); + self::assertSame($innodbPageSize, $bufferPool->innodbPageSize); + self::assertSame($pagesData, $bufferPool->pagesData); + self::assertSame($pagesDirty, $bufferPool->pagesDirty); + self::assertSame($pagesFlushed, $bufferPool->pagesFlushed); + self::assertSame($pagesFree, $bufferPool->pagesFree); + self::assertSame($pagesMisc, $bufferPool->pagesMisc); + self::assertSame($pagesTotal, $bufferPool->pagesTotal); + self::assertSame($readRequests, $bufferPool->readRequests); + self::assertSame($reads, $bufferPool->reads); + self::assertSame($waitFree, $bufferPool->waitFree); + self::assertSame($writeRequests, $bufferPool->writeRequests); + self::assertSame($pagesLatched, $bufferPool->pagesLatched); + } + + /** + * @return iterable, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string, + * numeric-string|null + * }> + */ + public static function resultProvider(): iterable + { + yield [[], '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', null]; + + $result = [ + 'Innodb_page_size' => '1', + 'Innodb_buffer_pool_pages_data' => '2', + 'Innodb_buffer_pool_pages_dirty' => '3', + 'Innodb_buffer_pool_pages_flushed' => '4', + 'Innodb_buffer_pool_pages_free' => '5', + 'Innodb_buffer_pool_pages_misc' => '6', + 'Innodb_buffer_pool_pages_total' => '7', + 'Innodb_buffer_pool_read_requests' => '8', + 'Innodb_buffer_pool_reads' => '9', + 'Innodb_buffer_pool_wait_free' => '10', + 'Innodb_buffer_pool_write_requests' => '11', + 'Innodb_buffer_pool_pages_latched' => '12', + ]; + + yield [$result, '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']; + + $result = [ + 'Innodb_page_size' => null, + 'Innodb_buffer_pool_pages_data' => null, + 'Innodb_buffer_pool_pages_dirty' => null, + 'Innodb_buffer_pool_pages_flushed' => null, + 'Innodb_buffer_pool_pages_free' => null, + 'Innodb_buffer_pool_pages_misc' => null, + 'Innodb_buffer_pool_pages_total' => null, + 'Innodb_buffer_pool_read_requests' => null, + 'Innodb_buffer_pool_reads' => null, + 'Innodb_buffer_pool_wait_free' => null, + 'Innodb_buffer_pool_write_requests' => null, + 'Innodb_buffer_pool_pages_latched' => null, + ]; + + yield [$result, '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', null]; + } +} diff --git a/tests/unit/Engines/InnodbTest.php b/tests/unit/Engines/InnodbTest.php index af82d0665b..888ae96ec5 100644 --- a/tests/unit/Engines/InnodbTest.php +++ b/tests/unit/Engines/InnodbTest.php @@ -141,13 +141,12 @@ class InnodbTest extends AbstractTestCase ): void { $dbiDummy = $this->createDbiDummy(); $dbiDummy->addResult( - 'SHOW STATUS WHERE Variable_name LIKE \'Innodb\\_buffer\\_pool\\_%\'' - . ' OR Variable_name = \'Innodb_page_size\';', + "SHOW STATUS WHERE Variable_name LIKE 'Innodb\\_buffer\\_pool\\_%' OR Variable_name = 'Innodb_page_size';", $variables, ); DatabaseInterface::$instance = $this->createDatabaseInterface($dbiDummy); - $pageBufferPool = (new Innodb('innodb'))->getPageBufferpool(); + $pageBufferPool = (new Innodb('innodb'))->getPageBufferPool(); $dbiDummy->assertAllQueriesConsumed(); $expected = '
' . "\n" @@ -131,7 +122,7 @@ class Innodb extends StorageEngine . '
' . "\n" . ' ' . __('Total:') . ' ' - . Util::formatNumber($status['Innodb_buffer_pool_pages_total'], 0) + . Util::formatNumber($status->pagesTotal, 0) . ' ' . __('pages') . ' / ' . implode(' ', $bytes) . "\n" @@ -142,40 +133,39 @@ class Innodb extends StorageEngine . '
' . __('Free pages') . '' - . Util::formatNumber($status['Innodb_buffer_pool_pages_free'], 0) + . Util::formatNumber($status->pagesFree, 0) . '
' . __('Dirty pages') . '' - . Util::formatNumber($status['Innodb_buffer_pool_pages_dirty'], 0) + . Util::formatNumber($status->pagesDirty, 0) . '
' . __('Pages containing data') . '' - . Util::formatNumber($status['Innodb_buffer_pool_pages_data'], 0) + . Util::formatNumber($status->pagesData, 0) . '
' . __('Pages to be flushed') . '' - . Util::formatNumber($status['Innodb_buffer_pool_pages_flushed'], 0) + . Util::formatNumber($status->pagesFlushed, 0) . '
' . __('Busy pages') . '' - . Util::formatNumber($status['Innodb_buffer_pool_pages_misc'], 0) + . Util::formatNumber($status->pagesMisc, 0) . '
' . __('Latched pages') . '' - . Util::formatNumber($status['Innodb_buffer_pool_pages_latched'], 0) + . Util::formatNumber($status->pagesLatched, 0) . '
' . __('Read requests') . '' - . Util::formatNumber($status['Innodb_buffer_pool_read_requests'], 0) + . Util::formatNumber($status->readRequests, 0) . '
' . __('Write requests') . '' - . Util::formatNumber($status['Innodb_buffer_pool_write_requests'], 0) + . Util::formatNumber($status->writeRequests, 0) . '
' . __('Read misses') . '' - . Util::formatNumber($status['Innodb_buffer_pool_reads'], 0) + . Util::formatNumber($status->reads, 0) . '
' . __('Write waits') . '' - . Util::formatNumber($status['Innodb_buffer_pool_wait_free'], 0) + . Util::formatNumber($status->waitFree, 0) . '
' . __('Read misses in %') . '' - . ($status['Innodb_buffer_pool_read_requests'] == 0 + . ((float) $status->readRequests === 0.0 ? '---' - : htmlspecialchars( - Util::formatNumber( - $status['Innodb_buffer_pool_reads'] * 100 - / $status['Innodb_buffer_pool_read_requests'], - 3, - 2, - ), - ) . ' %') + : htmlspecialchars(Util::formatNumber($status->reads * 100 / $status->readRequests, 3, 2)) . ' %') . '
' . __('Write waits in %') . '' - . ($status['Innodb_buffer_pool_write_requests'] == 0 + . ((float) $status->writeRequests === 0.0 ? '---' - : htmlspecialchars( - Util::formatNumber( - $status['Innodb_buffer_pool_wait_free'] * 100 - / $status['Innodb_buffer_pool_write_requests'], - 3, - 2, - ), - ) . ' %') + : htmlspecialchars(Util::formatNumber($status->waitFree * 100 / $status->writeRequests, 3, 2)) . ' %') . '
' . "\n" .