Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 77 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
PruneUnusedLinkTargetRows | |
0.00% |
0 / 74 |
|
0.00% |
0 / 2 |
90 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 61 |
|
0.00% |
0 / 1 |
72 |
1 | <?php |
2 | |
3 | require_once __DIR__ . '/Maintenance.php'; |
4 | |
5 | /** |
6 | * Maintenance script that cleans unused rows in linktarget table |
7 | * |
8 | * @ingroup Maintenance |
9 | * @since 1.39 |
10 | */ |
11 | class PruneUnusedLinkTargetRows extends Maintenance { |
12 | public function __construct() { |
13 | parent::__construct(); |
14 | $this->addDescription( |
15 | 'Clean unused rows in linktarget table' |
16 | ); |
17 | $this->addOption( |
18 | 'sleep', |
19 | 'Sleep time (in seconds) between every batch. Default: 0', |
20 | false, |
21 | true |
22 | ); |
23 | $this->addOption( 'dry', 'Dry run', false ); |
24 | $this->addOption( 'start', 'Start after this lt_id', false, true ); |
25 | $this->setBatchSize( 50 ); |
26 | } |
27 | |
28 | public function execute() { |
29 | $dbw = $this->getPrimaryDB(); |
30 | $dbr = $this->getReplicaDB(); |
31 | $maxLtId = (int)$dbr->newSelectQueryBuilder() |
32 | ->select( 'MAX(lt_id)' ) |
33 | ->from( 'linktarget' ) |
34 | ->fetchField(); |
35 | // To avoid race condition of newly added linktarget rows |
36 | // being deleted before getting a chance to be used, let's ignore the newest ones. |
37 | $maxLtId = min( [ $maxLtId - 1, (int)( $maxLtId * 0.99 ) ] ); |
38 | |
39 | $ltCounter = (int)$this->getOption( 'start', 0 ); |
40 | |
41 | $this->output( "Deleting unused linktarget rows...\n" ); |
42 | $deleted = 0; |
43 | $linksMigration = $this->getServiceContainer()->getLinksMigration(); |
44 | while ( $ltCounter < $maxLtId ) { |
45 | $batchMaxLtId = min( $ltCounter + $this->getBatchSize(), $maxLtId ) + 1; |
46 | $this->output( "Checking lt_id between $ltCounter and $batchMaxLtId...\n" ); |
47 | $queryBuilder = $dbr->newSelectQueryBuilder() |
48 | ->select( [ 'lt_id' ] ) |
49 | ->from( 'linktarget' ); |
50 | $queryBuilder->where( [ |
51 | $dbr->expr( 'lt_id', '<', $batchMaxLtId ), |
52 | $dbr->expr( 'lt_id', '>', $ltCounter ) |
53 | ] ); |
54 | foreach ( $linksMigration::$mapping as $table => $tableData ) { |
55 | $queryBuilder->leftJoin( $table, null, $tableData['target_id'] . '=lt_id' ); |
56 | $queryBuilder->andWhere( [ |
57 | $tableData['target_id'] => null |
58 | ] ); |
59 | } |
60 | $ltIdsToDelete = $queryBuilder->caller( __METHOD__ )->fetchFieldValues(); |
61 | if ( !$ltIdsToDelete ) { |
62 | $ltCounter += $this->getBatchSize(); |
63 | continue; |
64 | } |
65 | |
66 | // Run against primary as well with a faster query plan, just to be safe. |
67 | // Also having a bit of time in between helps in cases of immediate removal and insertion of use. |
68 | $queryBuilder = $dbr->newSelectQueryBuilder() |
69 | ->select( [ 'lt_id' ] ) |
70 | ->from( 'linktarget' ) |
71 | ->where( [ |
72 | 'lt_id' => $ltIdsToDelete, |
73 | ] ); |
74 | foreach ( $linksMigration::$mapping as $table => $tableData ) { |
75 | $queryBuilder->leftJoin( $table, null, $tableData['target_id'] . '=lt_id' ); |
76 | $queryBuilder->andWhere( [ |
77 | $tableData['target_id'] => null |
78 | ] ); |
79 | } |
80 | $ltIdsToDelete = $queryBuilder->caller( __METHOD__ )->fetchFieldValues(); |
81 | if ( !$ltIdsToDelete ) { |
82 | $ltCounter += $this->getBatchSize(); |
83 | continue; |
84 | } |
85 | |
86 | if ( !$this->getOption( 'dry' ) ) { |
87 | $dbw->newDeleteQueryBuilder() |
88 | ->deleteFrom( 'linktarget' ) |
89 | ->where( [ 'lt_id' => $ltIdsToDelete ] ) |
90 | ->caller( __METHOD__ )->execute(); |
91 | } |
92 | $deleted += count( $ltIdsToDelete ); |
93 | $ltCounter += $this->getBatchSize(); |
94 | |
95 | // Sleep between batches for replication to catch up |
96 | $this->waitForReplication(); |
97 | $sleep = (int)$this->getOption( 'sleep', 0 ); |
98 | if ( $sleep > 0 ) { |
99 | sleep( $sleep ); |
100 | } |
101 | } |
102 | |
103 | $this->output( |
104 | "Completed clean up linktarget table, " |
105 | . "$deleted rows deleted.\n" |
106 | ); |
107 | |
108 | return true; |
109 | } |
110 | |
111 | } |
112 | |
113 | $maintClass = PruneUnusedLinkTargetRows::class; |
114 | require_once RUN_MAINTENANCE_IF_MAIN; |