Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 52 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
RenameUserJob | |
0.00% |
0 / 51 |
|
0.00% |
0 / 2 |
110 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
run | |
0.00% |
0 / 48 |
|
0.00% |
0 / 1 |
90 |
1 | <?php |
2 | |
3 | namespace MediaWiki\RenameUser; |
4 | |
5 | use InvalidArgumentException; |
6 | use Job; |
7 | use MediaWiki\Config\Config; |
8 | use MediaWiki\MainConfigNames; |
9 | use MediaWiki\Title\Title; |
10 | use Wikimedia\Rdbms\ILBFactory; |
11 | |
12 | /** |
13 | * Custom job to perform updates on tables in busier environments |
14 | * |
15 | * Job parameters include: |
16 | * - table : DB table to update |
17 | * - column : The *_user_text column to update |
18 | * - oldname : The old user name |
19 | * - newname : The new user name |
20 | * - count : The expected number of rows to update in this batch |
21 | * |
22 | * Additionally, one of the following groups of parameters must be set: |
23 | * a) The timestamp based rename parameters: |
24 | * - timestampColumn : The *_timestamp column |
25 | * - minTimestamp : The minimum bound of the timestamp column range for this batch |
26 | * - maxTimestamp : The maximum bound of the timestamp column range for this batch |
27 | * - uniqueKey : A column that is unique (preferably the PRIMARY KEY) [optional] |
28 | * b) The unique key based rename parameters: |
29 | * - uniqueKey : A column that is unique (preferably the PRIMARY KEY) |
30 | * - keyId : A list of values for this column to determine rows to update for this batch |
31 | * |
32 | * To avoid some race conditions, the following parameters should be set: |
33 | * - userID : The ID of the user to update |
34 | * - uidColumn : The *_user_id column |
35 | */ |
36 | class RenameUserJob extends Job { |
37 | /** @var int */ |
38 | private $updateRowsPerQuery; |
39 | |
40 | /** @var ILBFactory */ |
41 | private $lbFactory; |
42 | |
43 | public function __construct( |
44 | Title $title, |
45 | $params, |
46 | Config $config, |
47 | ILBFactory $lbFactory |
48 | ) { |
49 | parent::__construct( 'renameUser', $title, $params ); |
50 | |
51 | $this->updateRowsPerQuery = $config->get( MainConfigNames::UpdateRowsPerQuery ); |
52 | $this->lbFactory = $lbFactory; |
53 | } |
54 | |
55 | public function run() { |
56 | $dbw = $this->lbFactory->getPrimaryDatabase(); |
57 | $ticket = $this->lbFactory->getEmptyTransactionTicket( __METHOD__ ); |
58 | $table = $this->params['table']; |
59 | $column = $this->params['column']; |
60 | |
61 | $oldname = $this->params['oldname']; |
62 | $newname = $this->params['newname']; |
63 | if ( isset( $this->params['userID'] ) ) { |
64 | $userID = $this->params['userID']; |
65 | $uidColumn = $this->params['uidColumn']; |
66 | } else { |
67 | $userID = null; |
68 | $uidColumn = null; |
69 | } |
70 | if ( isset( $this->params['timestampColumn'] ) ) { |
71 | $timestampColumn = $this->params['timestampColumn']; |
72 | $minTimestamp = $this->params['minTimestamp']; |
73 | $maxTimestamp = $this->params['maxTimestamp']; |
74 | } else { |
75 | $timestampColumn = null; |
76 | $minTimestamp = null; |
77 | $maxTimestamp = null; |
78 | } |
79 | $uniqueKey = $this->params['uniqueKey'] ?? null; |
80 | $keyId = $this->params['keyId'] ?? null; |
81 | |
82 | # Conditions like "*_user_text = 'x' |
83 | $conds = [ $column => $oldname ]; |
84 | # If user ID given, add that to condition to avoid rename collisions |
85 | if ( $userID !== null ) { |
86 | $conds[$uidColumn] = $userID; |
87 | } |
88 | # Bound by timestamp if given |
89 | if ( $timestampColumn !== null ) { |
90 | $conds[] = $dbw->expr( $timestampColumn, '>=', $minTimestamp ); |
91 | $conds[] = $dbw->expr( $timestampColumn, '<=', $maxTimestamp ); |
92 | # Bound by unique key if given (B/C) |
93 | } elseif ( $uniqueKey !== null && $keyId !== null ) { |
94 | $conds[$uniqueKey] = $keyId; |
95 | } else { |
96 | throw new InvalidArgumentException( 'Expected ID batch or time range' ); |
97 | } |
98 | |
99 | # Actually update the rows for this job... |
100 | if ( $uniqueKey !== null ) { |
101 | // Select the rows to update by PRIMARY KEY |
102 | $ids = $dbw->newSelectQueryBuilder() |
103 | ->select( $uniqueKey ) |
104 | ->from( $table ) |
105 | ->where( $conds ) |
106 | ->caller( __METHOD__ )->fetchFieldValues(); |
107 | # Update these rows by PRIMARY KEY to avoid replica lag |
108 | foreach ( array_chunk( $ids, $this->updateRowsPerQuery ) as $batch ) { |
109 | $this->lbFactory->commitAndWaitForReplication( __METHOD__, $ticket ); |
110 | |
111 | $dbw->newUpdateQueryBuilder() |
112 | ->update( $table ) |
113 | ->set( [ $column => $newname ] ) |
114 | ->where( [ $column => $oldname, $uniqueKey => $batch ] ) |
115 | ->caller( __METHOD__ )->execute(); |
116 | } |
117 | } else { |
118 | # Update the chunk of rows directly |
119 | $dbw->newUpdateQueryBuilder() |
120 | ->update( $table ) |
121 | ->set( [ $column => $newname ] ) |
122 | ->where( $conds ) |
123 | ->caller( __METHOD__ )->execute(); |
124 | } |
125 | |
126 | return true; |
127 | } |
128 | } |
129 | /** @deprecated class alias since 1.43 */ |
130 | class_alias( RenameUserJob::class, 'RenameUserJob' ); |