MediaWiki master
pruneUnusedLinkTargetRows.php
Go to the documentation of this file.
1<?php
2
3// @codeCoverageIgnoreStart
4require_once __DIR__ . '/Maintenance.php';
5// @codeCoverageIgnoreEnd
6
14 public function __construct() {
15 parent::__construct();
16 $this->addDescription(
17 'Clean unused rows in linktarget table'
18 );
19 $this->addOption(
20 'sleep',
21 'Sleep time (in seconds) between every batch. Default: 0',
22 false,
23 true
24 );
25 $this->addOption( 'dry', 'Dry run', false );
26 $this->addOption( 'start', 'Start after this lt_id', false, true );
27 $this->setBatchSize( 50 );
28 }
29
30 public function execute() {
31 $dbw = $this->getPrimaryDB();
32 $dbr = $this->getReplicaDB();
33 $maxLtId = (int)$dbr->newSelectQueryBuilder()
34 ->select( 'MAX(lt_id)' )
35 ->from( 'linktarget' )
36 ->caller( __METHOD__ )
37 ->fetchField();
38 // To avoid race condition of newly added linktarget rows
39 // being deleted before getting a chance to be used, let's ignore the newest ones.
40 $maxLtId = min( [ $maxLtId - 1, (int)( $maxLtId * 0.99 ) ] );
41
42 $ltCounter = (int)$this->getOption( 'start', 0 );
43
44 $this->output( "Deleting unused linktarget rows...\n" );
45 $deleted = 0;
46 $linksMigration = $this->getServiceContainer()->getLinksMigration();
47 while ( $ltCounter < $maxLtId ) {
48 $batchMaxLtId = min( $ltCounter + $this->getBatchSize(), $maxLtId ) + 1;
49 $this->output( "Checking lt_id between $ltCounter and $batchMaxLtId...\n" );
50 $queryBuilder = $dbr->newSelectQueryBuilder()
51 ->select( [ 'lt_id' ] )
52 ->from( 'linktarget' );
53 $queryBuilder->where( [
54 $dbr->expr( 'lt_id', '<', $batchMaxLtId ),
55 $dbr->expr( 'lt_id', '>', $ltCounter )
56 ] );
57 foreach ( $linksMigration::$mapping as $table => $tableData ) {
58 $queryBuilder->leftJoin( $table, null, $tableData['target_id'] . '=lt_id' );
59 $queryBuilder->andWhere( [
60 $tableData['target_id'] => null
61 ] );
62 }
63 $ltIdsToDelete = $queryBuilder->caller( __METHOD__ )->fetchFieldValues();
64 if ( !$ltIdsToDelete ) {
65 $ltCounter += $this->getBatchSize();
66 continue;
67 }
68
69 // Run against primary as well with a faster query plan, just to be safe.
70 // Also having a bit of time in between helps in cases of immediate removal and insertion of use.
71 $queryBuilder = $dbr->newSelectQueryBuilder()
72 ->select( [ 'lt_id' ] )
73 ->from( 'linktarget' )
74 ->where( [
75 'lt_id' => $ltIdsToDelete,
76 ] );
77 foreach ( $linksMigration::$mapping as $table => $tableData ) {
78 $queryBuilder->leftJoin( $table, null, $tableData['target_id'] . '=lt_id' );
79 $queryBuilder->andWhere( [
80 $tableData['target_id'] => null
81 ] );
82 }
83 $ltIdsToDelete = $queryBuilder->caller( __METHOD__ )->fetchFieldValues();
84 if ( !$ltIdsToDelete ) {
85 $ltCounter += $this->getBatchSize();
86 continue;
87 }
88
89 if ( !$this->getOption( 'dry' ) ) {
90 $dbw->newDeleteQueryBuilder()
91 ->deleteFrom( 'linktarget' )
92 ->where( [ 'lt_id' => $ltIdsToDelete ] )
93 ->caller( __METHOD__ )->execute();
94 }
95 $deleted += count( $ltIdsToDelete );
96 $ltCounter += $this->getBatchSize();
97
98 // Sleep between batches for replication to catch up
99 $this->waitForReplication();
100 $sleep = (int)$this->getOption( 'sleep', 0 );
101 if ( $sleep > 0 ) {
102 sleep( $sleep );
103 }
104 }
105
106 $this->output(
107 "Completed clean up linktarget table, "
108 . "$deleted rows deleted.\n"
109 );
110
111 return true;
112 }
113
114}
115
116// @codeCoverageIgnoreStart
117$maintClass = PruneUnusedLinkTargetRows::class;
118require_once RUN_MAINTENANCE_IF_MAIN;
119// @codeCoverageIgnoreEnd
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
output( $out, $channel=null)
Throw some output to the user.
waitForReplication()
Wait for replica DBs to catch up.
getServiceContainer()
Returns the main service container.
getBatchSize()
Returns batch size.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
setBatchSize( $s=0)
Maintenance script that cleans unused rows in linktarget table.