Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 98 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
RemoveOrphanedEvents | |
0.00% |
0 / 93 |
|
0.00% |
0 / 4 |
90 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getUpdateKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
doDBUpdates | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
6 | |||
doMajorBatch | |
0.00% |
0 / 70 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | /** |
3 | * Remove rows from echo_event that don't have corresponding rows in echo_notification or echo_email_batch. |
4 | * |
5 | * @ingroup Maintenance |
6 | */ |
7 | |
8 | use MediaWiki\Extension\Notifications\DbFactory; |
9 | |
10 | require_once getenv( 'MW_INSTALL_PATH' ) !== false |
11 | ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php' |
12 | : __DIR__ . '/../../../maintenance/Maintenance.php'; |
13 | |
14 | /** |
15 | * Maintenance script that removes orphaned event rows |
16 | * |
17 | * @ingroup Maintenance |
18 | */ |
19 | class RemoveOrphanedEvents extends LoggedUpdateMaintenance { |
20 | |
21 | public function __construct() { |
22 | parent::__construct(); |
23 | |
24 | $this->addDescription( "Remove rows from echo_event and echo_target_page that don't have corresponding " . |
25 | "rows in echo_notification or echo_email_batch" ); |
26 | |
27 | $this->setBatchSize( 500 ); |
28 | |
29 | $this->requireExtension( 'Echo' ); |
30 | } |
31 | |
32 | public function getUpdateKey() { |
33 | return __CLASS__; |
34 | } |
35 | |
36 | public function doDBUpdates() { |
37 | $startId = 0; |
38 | $dbFactory = DbFactory::newFromDefault(); |
39 | $dbr = $dbFactory->getEchoDb( DB_REPLICA ); |
40 | $maxId = (int)$dbr->newSelectQueryBuilder() |
41 | ->select( 'MAX(event_id)' ) |
42 | ->from( 'echo_event' ) |
43 | ->fetchField(); |
44 | $eventsProcessedTotal = 0; |
45 | $targetsProcessedTotal = 0; |
46 | while ( $startId < $maxId ) { |
47 | $startId += $this->getBatchSize() * 1000; |
48 | [ $eventsProcessed, $targetsProcessed ] = $this->doMajorBatch( $startId ); |
49 | $eventsProcessedTotal += $eventsProcessed; |
50 | $targetsProcessedTotal += $targetsProcessed; |
51 | } |
52 | $this->output( "In total, deleted $eventsProcessedTotal orphaned events and " . |
53 | "$targetsProcessedTotal target_page rows.\n" ); |
54 | |
55 | return true; |
56 | } |
57 | |
58 | private function doMajorBatch( $maxId ) { |
59 | $dbFactory = DbFactory::newFromDefault(); |
60 | $dbw = $dbFactory->getEchoDb( DB_PRIMARY ); |
61 | $dbr = $dbFactory->getEchoDb( DB_REPLICA ); |
62 | $iterator = new BatchRowIterator( |
63 | $dbr, |
64 | [ 'echo_event', 'echo_notification', 'echo_email_batch' ], |
65 | 'event_id', |
66 | $this->getBatchSize() |
67 | ); |
68 | $iterator->addJoinConditions( [ |
69 | 'echo_notification' => [ 'LEFT JOIN', 'notification_event=event_id' ], |
70 | 'echo_email_batch' => [ 'LEFT JOIN', 'eeb_event_id=event_id' ], |
71 | ] ); |
72 | $iterator->addConditions( [ |
73 | 'notification_user' => null, |
74 | 'eeb_user_id' => null, |
75 | 'event_id < ' . $maxId |
76 | ] ); |
77 | $iterator->setCaller( __METHOD__ ); |
78 | |
79 | $this->output( "Removing orphaned echo_event rows with max event_id of $maxId...\n" ); |
80 | |
81 | $eventsProcessed = 0; |
82 | $targetsProcessed = 0; |
83 | foreach ( $iterator as $batch ) { |
84 | $ids = []; |
85 | foreach ( $batch as $row ) { |
86 | $ids[] = $row->event_id; |
87 | } |
88 | $dbw->newDeleteQueryBuilder() |
89 | ->deleteFrom( 'echo_event' ) |
90 | ->where( [ 'event_id' => $ids ] ) |
91 | ->caller( __METHOD__ ) |
92 | ->execute(); |
93 | $eventsProcessed += $dbw->affectedRows(); |
94 | $dbw->newDeleteQueryBuilder() |
95 | ->deleteFrom( 'echo_target_page' ) |
96 | ->where( [ 'etp_event' => $ids ] ) |
97 | ->caller( __METHOD__ ) |
98 | ->execute(); |
99 | $targetsProcessed += $dbw->affectedRows(); |
100 | $this->output( "Deleted $eventsProcessed orphaned events and $targetsProcessed target_page rows.\n" ); |
101 | $this->waitForReplication(); |
102 | } |
103 | |
104 | $this->output( "Removing any remaining orphaned echo_target_page rows with max etp_event of $maxId...\n" ); |
105 | $iterator = new BatchRowIterator( |
106 | $dbr, |
107 | [ 'echo_target_page', 'echo_event' ], |
108 | 'etp_event', |
109 | $this->getBatchSize() |
110 | ); |
111 | $iterator->addJoinConditions( [ 'echo_event' => [ 'LEFT JOIN', 'event_id=etp_event' ] ] ); |
112 | $iterator->addConditions( |
113 | [ |
114 | 'event_type' => null, |
115 | 'etp_event < ' . $maxId |
116 | ] |
117 | ); |
118 | $iterator->addOptions( [ 'DISTINCT' ] ); |
119 | $iterator->setCaller( __METHOD__ ); |
120 | |
121 | $processed = 0; |
122 | foreach ( $iterator as $batch ) { |
123 | $ids = []; |
124 | foreach ( $batch as $row ) { |
125 | $ids[] = $row->etp_event; |
126 | } |
127 | $dbw->newDeleteQueryBuilder() |
128 | ->deleteFrom( 'echo_target_page' ) |
129 | ->where( [ 'etp_event' => $ids ] ) |
130 | ->caller( __METHOD__ ) |
131 | ->execute(); |
132 | $processed += $dbw->affectedRows(); |
133 | $this->output( "Deleted $processed orphaned target_page rows.\n" ); |
134 | $this->waitForReplication(); |
135 | } |
136 | |
137 | return [ $eventsProcessed, $targetsProcessed + $processed ]; |
138 | } |
139 | } |
140 | |
141 | $maintClass = RemoveOrphanedEvents::class; |
142 | require_once RUN_MAINTENANCE_IF_MAIN; |