Index: trunk/extensions/Renameuser/RenameUserJob.php |
— | — | @@ -0,0 +1,20 @@ |
| 2 | +<?php
|
| 3 | +
|
| 4 | +class RenameUserJob extends Job {
|
| 5 | + function __construct($title,$params) {
|
| 6 | + parent::__construct('renameUser', $title, $params);
|
| 7 | + }
|
| 8 | +
|
| 9 | + function run() {
|
| 10 | + $dbw = wfGetDB( DB_MASTER );
|
| 11 | + // Our keyId param will be an array of ids
|
| 12 | + $dbw->update( $this->params['table'],
|
| 13 | + array( $this->params['column'] => $this->params['newname'] ),
|
| 14 | + array( $this->params['column'] => $this->params['oldname'],
|
| 15 | + $this->params['uniqueKey'] => $this->params['keyId'] )
|
| 16 | + #,array( $dbw->lowPriorityOption() )
|
| 17 | + );
|
| 18 | + }
|
| 19 | +}
|
| 20 | +
|
| 21 | +?>
|
Index: trunk/extensions/Renameuser/SpecialRenameuser_body.php |
— | — | @@ -279,18 +279,23 @@ |
280 | 280 | $this->new = $new; |
281 | 281 | $this->uid = $uid; |
282 | 282 | |
| 283 | + // 1.5 schema |
283 | 284 | $this->tables = array( |
284 | | - // 1.5 schema |
285 | | - 'user' => 'user_name', |
286 | | - 'revision' => 'rev_user_text', |
287 | 285 | 'image' => 'img_user_text', |
288 | | - 'oldimage' => 'oi_user_text', |
289 | | - |
290 | | - // Very hot table, causes lag and deadlocks to update like this |
291 | | - /*'recentchanges' => 'rc_user_text'*/ |
| 286 | + 'oldimage' => 'oi_user_text' |
292 | 287 | ); |
| 288 | + $this->tablesJob = array(); |
| 289 | + // See if this is for large tables on large, busy, wikis |
| 290 | + if( wfQueriesMustScale() ) { |
| 291 | + $this->tablesJob['revision'] = array('rev_user_text','rev_id'); |
| 292 | + $this->tablesJob['recentchanges'] = array('rc_user_text','rc_id'); |
| 293 | + } else { |
| 294 | + $this->tables['revision'] = 'rev_user_text'; |
| 295 | + $this->tables['recentchanges'] = 'rc_user_text'; |
| 296 | + } |
293 | 297 | |
294 | 298 | global $wgRenameUserQuick; |
| 299 | + // As of 1.10, usernames are not indexed here; too slow for large wikis |
295 | 300 | if( !$wgRenameUserQuick ) |
296 | 301 | $this->tables['archive'] = 'ar_user_text'; |
297 | 302 | |
— | — | @@ -307,8 +312,16 @@ |
308 | 313 | wfProfileIn( $fname ); |
309 | 314 | |
310 | 315 | $dbw =& wfGetDB( DB_MASTER ); |
| 316 | + // Rename and touch the user before re-attributing edits, |
| 317 | + // this avoids users still being login in and making new edits while |
| 318 | + // being renamed, which leaves edits at the old name. |
| 319 | + $dbw->update( 'user', |
| 320 | + array( 'user_name' => $this->new, 'user_touched' => $dbw->timestamp() ), |
| 321 | + array( 'user_name' => $this->old ), |
| 322 | + $fname |
| 323 | + ); |
311 | 324 | |
312 | | - foreach ($this->tables as $table => $field) { |
| 325 | + foreach( $this->tables as $table => $field ) { |
313 | 326 | $dbw->update( $table, |
314 | 327 | array( $field => $this->new ), |
315 | 328 | array( $field => $this->old ), |
— | — | @@ -316,16 +329,60 @@ |
317 | 330 | #,array( $dbw->lowPriorityOption() ) |
318 | 331 | ); |
319 | 332 | } |
| 333 | + |
| 334 | + foreach( $this->tablesJob as $table => $params ) { |
| 335 | + $res = $dbw->select( $table, |
| 336 | + array( $params[0], $params[1] ), |
| 337 | + array( $params[0] => $this->old ) |
| 338 | + ); |
| 339 | + |
| 340 | + global $wgUpdateRowsPerJob; |
| 341 | + |
| 342 | + $batchSize = 500; // Lets not flood the job table! |
| 343 | + $jobSize = $wgUpdateRowsPerJob; // How many rows per job? |
320 | 344 | |
321 | | - $dbw->update( 'user', |
322 | | - array( 'user_touched' => $dbw->timestamp() ), |
323 | | - array( 'user_name' => $this->new ), |
324 | | - $fname |
325 | | - ); |
326 | | - |
| 345 | + $key = $params[1]; |
| 346 | + $jobParams = array(); |
| 347 | + $jobParams['table'] = $table; |
| 348 | + $jobParams['column'] = $params[0]; |
| 349 | + $jobParams['uniqueKey'] = $key; |
| 350 | + $jobParams['oldname'] = $this->old; |
| 351 | + $jobParams['newname'] = $this->new; |
| 352 | + |
| 353 | + $jobParams['keyId'] = array(); |
| 354 | + $jobRows = 0; |
| 355 | + $done = false; |
| 356 | + while ( !$done ) { |
| 357 | + $jobs = array(); |
| 358 | + for ( $i = 0; $i < $batchSize; $i++ ) { |
| 359 | + $row = $dbw->fetchObject( $res ); |
| 360 | + if ( !$row ) { |
| 361 | + # If there are any job rows left, add it to the queue as a job |
| 362 | + if( $jobRows > 0 ) { |
| 363 | + $jobs[] = Job::factory( 'renameUser', Title::newMainPage(), $jobParams ); |
| 364 | + $jobRows = 0; |
| 365 | + $jobParams['keyId'] = array(); |
| 366 | + } |
| 367 | + $done = true; |
| 368 | + break; |
| 369 | + } |
| 370 | + $jobParams['keyId'][] = $row->$key; |
| 371 | + $jobRows++; |
| 372 | + # Once a job has $jobSize rows, add it to the queue |
| 373 | + if( $jobRows >= $jobSize ) { |
| 374 | + $jobs[] = Job::factory( 'renameUser', Title::newMainPage(), $jobParams ); |
| 375 | + $jobRows = 0; |
| 376 | + $jobParams['keyId'] = array(); |
| 377 | + } |
| 378 | + } |
| 379 | + Job::batchInsert( $jobs ); |
| 380 | + } |
| 381 | + $dbw->freeResult( $res ); |
| 382 | + } |
| 383 | + |
327 | 384 | // Clear the user cache |
328 | 385 | $wgMemc->delete( "$wgDBname:user:id:{$this->uid}" ); |
329 | | - |
| 386 | + |
330 | 387 | // Inform authentication plugin of the change |
331 | 388 | $user = User::newFromId( $this->uid ); |
332 | 389 | $wgAuth->updateExternalDB( $user ); |
Index: trunk/extensions/Renameuser/SpecialRenameuser.php |
— | — | @@ -39,6 +39,9 @@ |
40 | 40 | $wgLogHeaders['renameuser'] = 'renameuserlogpagetext'; |
41 | 41 | $wgLogActions['renameuser/renameuser'] = 'renameuserlogentry'; |
42 | 42 | |
| 43 | +$wgJobClasses['renameUser'] = 'RenameUserJob'; |
| 44 | +$wgAutoloadClasses['RenameUserJob'] = dirname(__FILE__) . '/RenameUserJob.php'; |
| 45 | + |
43 | 46 | /** |
44 | 47 | * If this is set to true, then the archive table (deleted revisions) will |
45 | 48 | * not be updated. Defaults to the value of $wgMiserMode, since if that's on, |