Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
OrphanStats
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 3
42
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getExternalDB
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * Show some statistics on the blob_orphans table, created with trackBlobs.php.
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 * @ingroup Maintenance ExternalStorage
8 */
9
10use MediaWiki\Maintenance\Maintenance;
11use Wikimedia\Rdbms\IDatabase;
12
13// @codeCoverageIgnoreStart
14require_once __DIR__ . '/../Maintenance.php';
15// @codeCoverageIgnoreEnd
16
17/**
18 * Maintenance script that shows some statistics on the blob_orphans table,
19 * created with trackBlobs.php.
20 *
21 * @ingroup Maintenance ExternalStorage
22 */
23class OrphanStats extends Maintenance {
24    public function __construct() {
25        parent::__construct();
26        $this->addDescription(
27            "Show some statistics on the blob_orphans table, created with trackBlobs.php" );
28    }
29
30    protected function getExternalDB( int $db, string $cluster ): IDatabase {
31        $lbFactory = $this->getServiceContainer()->getDBLoadBalancerFactory();
32        $lb = $lbFactory->getExternalLB( $cluster );
33
34        return $lb->getMaintenanceConnectionRef( $db );
35    }
36
37    public function execute() {
38        if ( !$this->getDB( DB_PRIMARY )->tableExists( 'blob_orphans', __METHOD__ ) ) {
39            $this->fatalError( "blob_orphans doesn't seem to exist, need to run trackBlobs.php first" );
40        }
41        $dbr = $this->getReplicaDB();
42        $res = $dbr->newSelectQueryBuilder()
43            ->select( '*' )
44            ->from( 'blob_orphans' )
45            ->caller( __METHOD__ )->fetchResultSet();
46
47        $num = 0;
48        $totalSize = 0;
49        $hashes = [];
50        $maxSize = 0;
51
52        foreach ( $res as $row ) {
53            $extDB = $this->getExternalDB( DB_REPLICA, $row->bo_cluster );
54            $blobRow = $extDB->newSelectQueryBuilder()
55                ->select( '*' )
56                ->from( 'blobs' )
57                ->where( [ 'blob_id' => $row->bo_blob_id ] )
58                ->caller( __METHOD__ )->fetchRow();
59
60            $num++;
61            $size = strlen( $blobRow->blob_text );
62            $totalSize += $size;
63            $hashes[sha1( $blobRow->blob_text )] = true;
64            $maxSize = max( $size, $maxSize );
65        }
66        unset( $res );
67
68        $this->output( "Number of orphans: $num\n" );
69        if ( $num > 0 ) {
70            $this->output( "Average size: " . round( $totalSize / $num, 0 ) . " bytes\n" .
71                "Max size: $maxSize\n" .
72                "Number of unique texts: " . count( $hashes ) . "\n" );
73        }
74    }
75}
76
77// @codeCoverageIgnoreStart
78$maintClass = OrphanStats::class;
79require_once RUN_MAINTENANCE_IF_MAIN;
80// @codeCoverageIgnoreEnd