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 | $table = $this->params['table']; |
58 | $column = $this->params['column']; |
59 | |
60 | $oldname = $this->params['oldname']; |
61 | $newname = $this->params['newname']; |
62 | if ( isset( $this->params['userID'] ) ) { |
63 | $userID = $this->params['userID']; |
64 | $uidColumn = $this->params['uidColumn']; |
65 | } else { |
66 | $userID = null; |
67 | $uidColumn = null; |
68 | } |
69 | if ( isset( $this->params['timestampColumn'] ) ) { |
70 | $timestampColumn = $this->params['timestampColumn']; |
71 | $minTimestamp = $this->params['minTimestamp']; |
72 | $maxTimestamp = $this->params['maxTimestamp']; |
73 | } else { |
74 | $timestampColumn = null; |
75 | $minTimestamp = null; |
76 | $maxTimestamp = null; |
77 | } |
78 | $uniqueKey = $this->params['uniqueKey'] ?? null; |
79 | $keyId = $this->params['keyId'] ?? null; |
80 | |
81 | # Conditions like "*_user_text = 'x' |
82 | $conds = [ $column => $oldname ]; |
83 | # If user ID given, add that to condition to avoid rename collisions |
84 | if ( $userID !== null ) { |
85 | $conds[$uidColumn] = $userID; |
86 | } |
87 | # Bound by timestamp if given |
88 | if ( $timestampColumn !== null ) { |
89 | $conds[] = $dbw->expr( $timestampColumn, '>=', $minTimestamp ); |
90 | $conds[] = $dbw->expr( $timestampColumn, '<=', $maxTimestamp ); |
91 | # Bound by unique key if given (B/C) |
92 | } elseif ( $uniqueKey !== null && $keyId !== null ) { |
93 | $conds[$uniqueKey] = $keyId; |
94 | } else { |
95 | throw new InvalidArgumentException( 'Expected ID batch or time range' ); |
96 | } |
97 | |
98 | # Actually update the rows for this job... |
99 | if ( $uniqueKey !== null ) { |
100 | // Select the rows to update by PRIMARY KEY |
101 | $ids = $dbw->newSelectQueryBuilder() |
102 | ->select( $uniqueKey ) |
103 | ->from( $table ) |
104 | ->where( $conds ) |
105 | ->caller( __METHOD__ )->fetchFieldValues(); |
106 | # Update these rows by PRIMARY KEY to avoid replica lag |
107 | foreach ( array_chunk( $ids, $this->updateRowsPerQuery ) as $batch ) { |
108 | $dbw->commit( __METHOD__, 'flush' ); |
109 | $this->lbFactory->waitForReplication(); |
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' ); |