Index: branches/maintenance-work/maintenance/removeUnusedAccounts.inc |
— | — | @@ -1,46 +0,0 @@ |
2 | | -<?php |
3 | | - |
4 | | -/** |
5 | | - * Support functions for the removeUnusedAccounts maintenance script |
6 | | - * |
7 | | - * @file |
8 | | - * @ingroup Maintenance |
9 | | - * @author Rob Church <robchur@gmail.com> |
10 | | - */ |
11 | | - |
12 | | -/** |
13 | | - * Could the specified user account be deemed inactive? |
14 | | - * (No edits, no deleted edits, no log entries, no current/old uploads) |
15 | | - * |
16 | | - * @param $id User's ID |
17 | | - * @param $master Perform checking on the master |
18 | | - * @return bool |
19 | | - */ |
20 | | -function isInactiveAccount( $id, $master = false ) { |
21 | | - $dbo = wfGetDB( $master ? DB_MASTER : DB_SLAVE ); |
22 | | - $fname = 'isInactiveAccount'; |
23 | | - $checks = array( 'revision' => 'rev', 'archive' => 'ar', 'logging' => 'log', |
24 | | - 'image' => 'img', 'oldimage' => 'oi' ); |
25 | | - $count = 0; |
26 | | - |
27 | | - $dbo->immediateBegin(); |
28 | | - foreach( $checks as $table => $fprefix ) { |
29 | | - $conds = array( $fprefix . '_user' => $id ); |
30 | | - $count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, $fname ); |
31 | | - } |
32 | | - $dbo->immediateCommit(); |
33 | | - |
34 | | - return $count == 0; |
35 | | -} |
36 | | - |
37 | | -/** |
38 | | - * Show help for the maintenance script |
39 | | - */ |
40 | | -function showHelp() { |
41 | | - echo( "Delete unused user accounts from the database.\n\n" ); |
42 | | - echo( "USAGE: php removeUnusedAccounts.php [--delete]\n\n" ); |
43 | | - echo( " --delete : Delete accounts which are discovered to be inactive\n" ); |
44 | | - echo( " --ignore-touched=x : Ignore accounts touched within the lasts x days\n" ); |
45 | | - echo( " --ignore-groups=x,y : Ignore accounts within these groups\n" ); |
46 | | - echo( "\n" ); |
47 | | -} |
Index: branches/maintenance-work/maintenance/populateParentId.inc |
— | — | @@ -1,83 +0,0 @@ |
2 | | -<?php |
3 | | - |
4 | | -define( 'BATCH_SIZE', 200 ); |
5 | | - |
6 | | -function populate_rev_parent_id( $db ) { |
7 | | - wfOut( "Populating rev_parent_id column\n" ); |
8 | | - $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __FUNCTION__ ); |
9 | | - $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ ); |
10 | | - if( is_null( $start ) || is_null( $end ) ){ |
11 | | - wfOut( "...revision table seems to be empty.\n" ); |
12 | | - $db->insert( 'updatelog', |
13 | | - array( 'ul_key' => 'populate rev_parent_id' ), |
14 | | - __FUNCTION__, |
15 | | - 'IGNORE' ); |
16 | | - return; |
17 | | - } |
18 | | - # Do remaining chunk |
19 | | - $end += BATCH_SIZE - 1; |
20 | | - $blockStart = intval( $start ); |
21 | | - $blockEnd = intval( $start ) + BATCH_SIZE - 1; |
22 | | - $count = 0; |
23 | | - $changed = 0; |
24 | | - while( $blockEnd <= $end ) { |
25 | | - wfOut( "...doing rev_id from $blockStart to $blockEnd\n" ); |
26 | | - $cond = "rev_id BETWEEN $blockStart AND $blockEnd"; |
27 | | - $res = $db->select( 'revision', |
28 | | - array('rev_id','rev_page','rev_timestamp','rev_parent_id'), |
29 | | - $cond, __FUNCTION__ ); |
30 | | - # Go through and update rev_parent_id from these rows. |
31 | | - # Assume that the previous revision of the title was |
32 | | - # the original previous revision of the title when the |
33 | | - # edit was made... |
34 | | - foreach( $res as $row ) { |
35 | | - # First, check rows with the same timestamp other than this one |
36 | | - # with a smaller rev ID. The highest ID "wins". This avoids loops |
37 | | - # as timestamp can only decrease and never loops with IDs (from parent to parent) |
38 | | - $previousID = $db->selectField( 'revision', 'rev_id', |
39 | | - array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $row->rev_timestamp, |
40 | | - "rev_id < " . intval( $row->rev_id ) ), |
41 | | - __FUNCTION__, |
42 | | - array( 'ORDER BY' => 'rev_id DESC' ) ); |
43 | | - # If there are none, check the the highest ID with a lower timestamp |
44 | | - if( !$previousID ) { |
45 | | - # Get the highest older timestamp |
46 | | - $lastTimestamp = $db->selectField( 'revision', 'rev_timestamp', |
47 | | - array( 'rev_page' => $row->rev_page, "rev_timestamp < " . $db->addQuotes( $row->rev_timestamp ) ), |
48 | | - __FUNCTION__, |
49 | | - array( 'ORDER BY' => 'rev_timestamp DESC' ) ); |
50 | | - # If there is one, let the highest rev ID win |
51 | | - if( $lastTimestamp ) { |
52 | | - $previousID = $db->selectField( 'revision', 'rev_id', |
53 | | - array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $lastTimestamp ), |
54 | | - __FUNCTION__, |
55 | | - array( 'ORDER BY' => 'rev_id DESC' ) ); |
56 | | - } |
57 | | - } |
58 | | - $previousID = intval($previousID); |
59 | | - if( $previousID != $row->rev_parent_id ) |
60 | | - $changed++; |
61 | | - # Update the row... |
62 | | - $db->update( 'revision', |
63 | | - array( 'rev_parent_id' => $previousID ), |
64 | | - array( 'rev_id' => $row->rev_id ), |
65 | | - __FUNCTION__ ); |
66 | | - $count++; |
67 | | - } |
68 | | - $blockStart += BATCH_SIZE - 1; |
69 | | - $blockEnd += BATCH_SIZE - 1; |
70 | | - wfWaitForSlaves( 5 ); |
71 | | - } |
72 | | - $logged = $db->insert( 'updatelog', |
73 | | - array( 'ul_key' => 'populate rev_parent_id' ), |
74 | | - __FUNCTION__, |
75 | | - 'IGNORE' ); |
76 | | - if( $logged ) { |
77 | | - wfOut( "rev_parent_id population complete ... {$count} rows [{$changed} changed]\n" ); |
78 | | - return true; |
79 | | - } else { |
80 | | - wfOut( "Could not insert rev_parent_id population row.\n" ); |
81 | | - return false; |
82 | | - } |
83 | | -} |
84 | | - |
Index: branches/maintenance-work/maintenance/mctest.php |
— | — | @@ -8,58 +8,63 @@ |
9 | 9 | * @ingroup Maintenance |
10 | 10 | */ |
11 | 11 | |
12 | | -$optionsWithArgs = array( 'i' ); |
| 12 | +require_once( "Maintenance.php" ); |
13 | 13 | |
14 | | -require_once('commandLine.inc'); |
| 14 | +class mcTest extends Maintenance { |
| 15 | + public function __construct() { |
| 16 | + parent::__construct(); |
| 17 | + $this->mDescription = "Makes several 'set', 'incr' and 'get' requests on every" |
| 18 | + . " memcached server and shows a report"; |
| 19 | + $this->addParam( 'i', 'Number of iterations', false, true ); |
| 20 | + $this->addArgs( array( 'server' ) ); |
| 21 | + } |
15 | 22 | |
16 | | -function microtime_float() |
17 | | -{ |
18 | | - list($usec, $sec) = explode(" ", microtime()); |
19 | | - return ((float)$usec + (float)$sec); |
20 | | -} |
| 23 | + public function execute() { |
| 24 | + global $wgMemCachedServers; |
21 | 25 | |
| 26 | + $iterations = $this->getOption( 'i', 100 ); |
| 27 | + if( $this->hasArg() ) |
| 28 | + $wgMemCachedServers = array( $this->getArg() ); |
22 | 29 | |
23 | | -#$wgDebugLogFile = '/dev/stdout'; |
24 | | - |
25 | | -if ( isset( $args[0] ) ) { |
26 | | - $wgMemCachedServers = array( $args[0] ); |
27 | | -} |
28 | | -if ( isset( $options['i'] ) ) { |
29 | | - $iterations = $options['i']; |
30 | | -} else { |
31 | | - $iterations = 100; |
32 | | -} |
33 | | - |
34 | | -foreach ( $wgMemCachedServers as $server ) { |
35 | | - print "$server "; |
36 | | - $mcc = new MemCachedClientforWiki( array('persistant' => true) ); |
37 | | - $mcc->set_servers( array( $server ) ); |
38 | | - $set = 0; |
39 | | - $incr = 0; |
40 | | - $get = 0; |
41 | | - $time_start=microtime_float(); |
42 | | - for ( $i=1; $i<=$iterations; $i++ ) { |
43 | | - if ( !is_null( $mcc->set( "test$i", $i ) ) ) { |
44 | | - $set++; |
| 30 | + foreach ( $wgMemCachedServers as $server ) { |
| 31 | + $this->output( $server . " " ); |
| 32 | + $mcc = new MemCachedClientforWiki( array('persistant' => true) ); |
| 33 | + $mcc->set_servers( array( $server ) ); |
| 34 | + $set = 0; |
| 35 | + $incr = 0; |
| 36 | + $get = 0; |
| 37 | + $time_start = $this->microtime_float(); |
| 38 | + for ( $i=1; $i<=$iterations; $i++ ) { |
| 39 | + if ( !is_null( $mcc->set( "test$i", $i ) ) ) { |
| 40 | + $set++; |
| 41 | + } |
| 42 | + } |
| 43 | + for ( $i=1; $i<=$iterations; $i++ ) { |
| 44 | + if ( !is_null( $mcc->incr( "test$i", $i ) ) ) { |
| 45 | + $incr++; |
| 46 | + } |
| 47 | + } |
| 48 | + for ( $i=1; $i<=$iterations; $i++ ) { |
| 49 | + $value = $mcc->get( "test$i" ); |
| 50 | + if ( $value == $i*2 ) { |
| 51 | + $get++; |
| 52 | + } |
| 53 | + } |
| 54 | + $exectime = $this->microtime_float() - $time_start; |
| 55 | + |
| 56 | + $this->output( "set: $set incr: $incr get: $get time: $exectime\n" ); |
45 | 57 | } |
46 | 58 | } |
47 | 59 | |
48 | | - for ( $i=1; $i<=$iterations; $i++ ) { |
49 | | - if ( !is_null( $mcc->incr( "test$i", $i ) ) ) { |
50 | | - $incr++; |
51 | | - } |
| 60 | + /** |
| 61 | + * Return microtime() as a float |
| 62 | + * @return float |
| 63 | + */ |
| 64 | + private function microtime_float() { |
| 65 | + list($usec, $sec) = explode(" ", microtime()); |
| 66 | + return ((float)$usec + (float)$sec); |
52 | 67 | } |
53 | | - |
54 | | - for ( $i=1; $i<=$iterations; $i++ ) { |
55 | | - $value = $mcc->get( "test$i" ); |
56 | | - if ( $value == $i*2 ) { |
57 | | - $get++; |
58 | | - } |
59 | | - } |
60 | | - $exectime=microtime_float()-$time_start; |
61 | | - |
62 | | - print "set: $set incr: $incr get: $get time: $exectime\n"; |
63 | 68 | } |
64 | 69 | |
65 | | - |
66 | | - |
| 70 | +$maintClass = "mcTest"; |
| 71 | +require_once( DO_MAINTENANCE ); |
Index: branches/maintenance-work/maintenance/checkBadRedirects.php |
— | — | @@ -1,30 +1,42 @@ |
2 | 2 | <?php |
| 3 | +/** |
| 4 | + * CheckBadRedirects - See if pages marked as being redirects |
| 5 | + * really are. |
| 6 | + */ |
| 7 | + |
| 8 | +require_once( "Maintenance.php" ); |
3 | 9 | |
4 | | -require "commandLine.inc"; |
| 10 | +class CheckBadRedirects extends Maintenance { |
| 11 | + public function __construct() { |
| 12 | + parent::__construct(); |
| 13 | + $this->mDescription = "Look for bad redirects"; |
| 14 | + } |
5 | 15 | |
6 | | -echo "Fetching redirects...\n"; |
7 | | -$dbr = wfGetDB( DB_SLAVE ); |
8 | | -$result = $dbr->select( |
9 | | - array( 'page' ), |
10 | | - array( 'page_namespace','page_title', 'page_latest' ), |
11 | | - array( 'page_is_redirect' => 1 ) ); |
12 | | - |
13 | | -$count = $result->numRows(); |
14 | | -echo "Found $count total redirects.\n"; |
15 | | -echo "Looking for bad redirects:\n"; |
16 | | -echo "\n"; |
17 | | - |
18 | | -foreach( $result as $row ) { |
19 | | - $title = Title::makeTitle( $row->page_namespace, $row->page_title ); |
20 | | - $rev = Revision::newFromId( $row->page_latest ); |
21 | | - if( $rev ) { |
22 | | - $target = Title::newFromRedirect( $rev->getText() ); |
23 | | - if( !$target ) { |
24 | | - echo $title->getPrefixedText(); |
25 | | - echo "\n"; |
| 16 | + public function execute() { |
| 17 | + $this->output( "Fetching redirects...\n" ); |
| 18 | + $dbr = wfGetDB( DB_SLAVE ); |
| 19 | + $result = $dbr->select( |
| 20 | + array( 'page' ), |
| 21 | + array( 'page_namespace','page_title', 'page_latest' ), |
| 22 | + array( 'page_is_redirect' => 1 ) ); |
| 23 | + |
| 24 | + $count = $result->numRows(); |
| 25 | + $this->output( "Found $count total redirects.\n" . |
| 26 | + "Looking for bad redirects:\n\n" ); |
| 27 | + |
| 28 | + foreach( $result as $row ) { |
| 29 | + $title = Title::makeTitle( $row->page_namespace, $row->page_title ); |
| 30 | + $rev = Revision::newFromId( $row->page_latest ); |
| 31 | + if( $rev ) { |
| 32 | + $target = Title::newFromRedirect( $rev->getText() ); |
| 33 | + if( !$target ) { |
| 34 | + $this->output( $title->getPrefixedText() . "\n" ); |
| 35 | + } |
| 36 | + } |
26 | 37 | } |
| 38 | + $this->output( "\ndone.\n" ); |
27 | 39 | } |
28 | 40 | } |
29 | 41 | |
30 | | -echo "\n"; |
31 | | -echo "done.\n"; |
| 42 | +$maintClass = "CheckBadRedirects"; |
| 43 | +require_once( DO_MAINTENANCE ); |
Index: branches/maintenance-work/maintenance/rebuildFileCache.php |
— | — | @@ -6,87 +6,96 @@ |
7 | 7 | * @ingroup Maintenance |
8 | 8 | */ |
9 | 9 | |
10 | | -/** */ |
11 | | -require_once( "commandLine.inc" ); |
12 | | -if( !$wgUseFileCache ) { |
13 | | - echo "Nothing to do -- \$wgUseFileCache is disabled.\n"; |
14 | | - exit(0); |
15 | | -} |
16 | | -$wgDisableCounters = false; // no real hits here |
| 10 | +require_once( "Maintenance.php" ); |
17 | 11 | |
18 | | -$start = isset($args[0]) ? intval($args[0]) : 0; |
19 | | -$overwrite = isset( $args[1] ) && $args[1] === 'overwrite'; |
20 | | -echo "Building content page file cache from page {$start}!\n"; |
21 | | -echo "Format: <start> [overwrite]\n"; |
| 12 | +class RebuildFileCache extends Maintenance { |
| 13 | + public function __construct() { |
| 14 | + parent::__construct(); |
| 15 | + $this->mDescription = "Build file cache for content pages"; |
| 16 | + $this->addArgs( array( 'start', 'overwrite' ) ); |
| 17 | + } |
22 | 18 | |
23 | | -$dbr = wfGetDB( DB_SLAVE ); |
24 | | -$start = $start > 0 ? $start : $dbr->selectField( 'page', 'MIN(page_id)', false, __FUNCTION__ ); |
25 | | -$end = $dbr->selectField( 'page', 'MAX(page_id)', false, __FUNCTION__ ); |
26 | | -if( !$start ) { |
27 | | - die("Nothing to do.\n"); |
28 | | -} |
29 | | - |
30 | | -$_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client |
31 | | -OutputPage::setEncodings(); # Not really used yet |
32 | | - |
33 | | -$BATCH_SIZE = 100; |
34 | | -# Do remaining chunk |
35 | | -$end += $BATCH_SIZE - 1; |
36 | | -$blockStart = $start; |
37 | | -$blockEnd = $start + $BATCH_SIZE - 1; |
38 | | - |
39 | | -$dbw = wfGetDB( DB_MASTER ); |
40 | | -// Go through each page and save the output |
41 | | -while( $blockEnd <= $end ) { |
42 | | - // Get the pages |
43 | | - $res = $dbr->select( 'page', array('page_namespace','page_title','page_id'), |
44 | | - array('page_namespace' => $wgContentNamespaces, |
45 | | - "page_id BETWEEN $blockStart AND $blockEnd" ), |
46 | | - array('ORDER BY' => 'page_id ASC','USE INDEX' => 'PRIMARY') |
47 | | - ); |
48 | | - while( $row = $dbr->fetchObject( $res ) ) { |
49 | | - $rebuilt = false; |
50 | | - $wgTitle = Title::makeTitleSafe( $row->page_namespace, $row->page_title ); |
51 | | - if( null == $wgTitle ) { |
52 | | - echo "Page {$row->page_id} bad title\n"; |
53 | | - continue; // broken title? |
| 19 | + public function execute() { |
| 20 | + global $wgUseFileCache, $wgDisableCounters, $wgTitle, $wgArticle, $wgOut; |
| 21 | + if( !$wgUseFileCache ) { |
| 22 | + $this->error( "Nothing to do -- \$wgUseFileCache is disabled.\n", true ); |
54 | 23 | } |
55 | | - $wgArticle = new Article( $wgTitle ); |
56 | | - // If the article is cacheable, then load it |
57 | | - if( $wgArticle->isFileCacheable() ) { |
58 | | - $cache = new HTMLFileCache( $wgTitle ); |
59 | | - if( $cache->isFileCacheGood() ) { |
60 | | - if( $overwrite ) { |
61 | | - $rebuilt = true; |
| 24 | + $wgDisableCounters = false; |
| 25 | + $start = intval( $this->getArg( 0, 0 ) ); |
| 26 | + $overwrite = $this->hasArg(1) && $this->getArg(1) === 'overwrite'; |
| 27 | + $this->output( "Building content page file cache from page {$start}!\n" ); |
| 28 | + |
| 29 | + $dbr = wfGetDB( DB_SLAVE ); |
| 30 | + $start = $start > 0 ? $start : $dbr->selectField( 'page', 'MIN(page_id)', false, __FUNCTION__ ); |
| 31 | + $end = $dbr->selectField( 'page', 'MAX(page_id)', false, __FUNCTION__ ); |
| 32 | + if( !$start ) { |
| 33 | + $this->error( "Nothing to do.\n", true ); |
| 34 | + } |
| 35 | + |
| 36 | + $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client |
| 37 | + OutputPage::setEncodings(); # Not really used yet |
| 38 | + |
| 39 | + $BATCH_SIZE = 100; |
| 40 | + # Do remaining chunk |
| 41 | + $end += $BATCH_SIZE - 1; |
| 42 | + $blockStart = $start; |
| 43 | + $blockEnd = $start + $BATCH_SIZE - 1; |
| 44 | + |
| 45 | + $dbw = wfGetDB( DB_MASTER ); |
| 46 | + // Go through each page and save the output |
| 47 | + while( $blockEnd <= $end ) { |
| 48 | + // Get the pages |
| 49 | + $res = $dbr->select( 'page', array('page_namespace','page_title','page_id'), |
| 50 | + array('page_namespace' => $wgContentNamespaces, |
| 51 | + "page_id BETWEEN $blockStart AND $blockEnd" ), |
| 52 | + array('ORDER BY' => 'page_id ASC','USE INDEX' => 'PRIMARY') |
| 53 | + ); |
| 54 | + while( $row = $dbr->fetchObject( $res ) ) { |
| 55 | + $rebuilt = false; |
| 56 | + $wgTitle = Title::makeTitleSafe( $row->page_namespace, $row->page_title ); |
| 57 | + if( null == $wgTitle ) { |
| 58 | + $this->output( "Page {$row->page_id} bad title\n" ); |
| 59 | + continue; // broken title? |
| 60 | + } |
| 61 | + $wgArticle = new Article( $wgTitle ); |
| 62 | + // If the article is cacheable, then load it |
| 63 | + if( $wgArticle->isFileCacheable() ) { |
| 64 | + $cache = new HTMLFileCache( $wgTitle ); |
| 65 | + if( $cache->isFileCacheGood() ) { |
| 66 | + if( $overwrite ) { |
| 67 | + $rebuilt = true; |
| 68 | + } else { |
| 69 | + $this->output( "Page {$row->page_id} already cached\n" ); |
| 70 | + continue; // done already! |
| 71 | + } |
| 72 | + } |
| 73 | + ob_start( array(&$cache, 'saveToFileCache' ) ); // save on ob_end_clean() |
| 74 | + $wgUseFileCache = false; // hack, we don't want $wgArticle fiddling with filecache |
| 75 | + $wgArticle->view(); |
| 76 | + @$wgOut->output(); // header notices |
| 77 | + $wgUseFileCache = true; |
| 78 | + ob_end_clean(); // clear buffer |
| 79 | + $wgOut = new OutputPage(); // empty out any output page garbage |
| 80 | + if( $rebuilt ) |
| 81 | + $this->output( "Re-cached page {$row->page_id}\n" ); |
| 82 | + else |
| 83 | + $this->output( "Cached page {$row->page_id}\n" ); |
62 | 84 | } else { |
63 | | - echo "Page {$row->page_id} already cached\n"; |
64 | | - continue; // done already! |
| 85 | + $this->output( "Page {$row->page_id} not cacheable\n" ); |
65 | 86 | } |
| 87 | + $dbw->commit(); // commit any changes |
66 | 88 | } |
67 | | - ob_start( array(&$cache, 'saveToFileCache' ) ); // save on ob_end_clean() |
68 | | - $wgUseFileCache = false; // hack, we don't want $wgArticle fiddling with filecache |
69 | | - $wgArticle->view(); |
70 | | - @$wgOut->output(); // header notices |
71 | | - $wgUseFileCache = true; |
72 | | - ob_end_clean(); // clear buffer |
73 | | - $wgOut = new OutputPage(); // empty out any output page garbage |
74 | | - if( $rebuilt ) |
75 | | - echo "Re-cached page {$row->page_id}\n"; |
76 | | - else |
77 | | - echo "Cached page {$row->page_id}\n"; |
78 | | - } else { |
79 | | - echo "Page {$row->page_id} not cacheable\n"; |
| 89 | + $blockStart += $BATCH_SIZE; |
| 90 | + $blockEnd += $BATCH_SIZE; |
| 91 | + wfWaitForSlaves( 5 ); |
80 | 92 | } |
81 | | - $dbw->commit(); // commit any changes |
| 93 | + $this->output( "Done!\n" ); |
| 94 | + |
| 95 | + // Remove these to be safe |
| 96 | + if( isset($wgTitle) ) |
| 97 | + unset($wgTitle); |
| 98 | + if( isset($wgArticle) ) |
| 99 | + unset($wgArticle); |
82 | 100 | } |
83 | | - $blockStart += $BATCH_SIZE; |
84 | | - $blockEnd += $BATCH_SIZE; |
85 | | - wfWaitForSlaves( 5 ); |
86 | 101 | } |
87 | | -echo "Done!\n"; |
88 | | - |
89 | | -// Remove these to be safe |
90 | | -if( isset($wgTitle) ) |
91 | | - unset($wgTitle); |
92 | | -if( isset($wgArticle) ) |
93 | | - unset($wgArticle); |
| 102 | +require_once( "commandLine.inc" ); |
Index: branches/maintenance-work/maintenance/getLagTimes.php |
— | — | @@ -4,26 +4,37 @@ |
5 | 5 | * @ingroup Maintenance |
6 | 6 | */ |
7 | 7 | |
8 | | -require 'commandLine.inc'; |
| 8 | +require_once( "Maintenance.php" ); |
9 | 9 | |
10 | | -$lb = wfGetLB(); |
| 10 | +class GetLagTimes extends Maintenance { |
| 11 | + public function __construct() { |
| 12 | + parent::__construct(); |
| 13 | + $this->mDescription = "Dump replication lag times"; |
| 14 | + } |
11 | 15 | |
12 | | -if( $lb->getServerCount() == 1 ) { |
13 | | - echo "This script dumps replication lag times, but you don't seem to have\n"; |
14 | | - echo "a multi-host db server configuration.\n"; |
15 | | -} else { |
16 | | - $lags = $lb->getLagTimes(); |
17 | | - foreach( $lags as $n => $lag ) { |
18 | | - $host = $lb->getServerName( $n ); |
19 | | - if( IP::isValid( $host ) ) { |
20 | | - $ip = $host; |
21 | | - $host = gethostbyaddr( $host ); |
| 16 | + public function execute() { |
| 17 | + $lb = wfGetLB(); |
| 18 | + |
| 19 | + if( $lb->getServerCount() == 1 ) { |
| 20 | + $this->error( "This script dumps replication lag times, but you don't seem to have\n" |
| 21 | + . "a multi-host db server configuration.\n" ); |
22 | 22 | } else { |
23 | | - $ip = gethostbyname( $host ); |
| 23 | + $lags = $lb->getLagTimes(); |
| 24 | + foreach( $lags as $n => $lag ) { |
| 25 | + $host = $lb->getServerName( $n ); |
| 26 | + if( IP::isValid( $host ) ) { |
| 27 | + $ip = $host; |
| 28 | + $host = gethostbyaddr( $host ); |
| 29 | + } else { |
| 30 | + $ip = gethostbyname( $host ); |
| 31 | + } |
| 32 | + $starLen = min( intval( $lag ), 40 ); |
| 33 | + $stars = str_repeat( '*', $starLen ); |
| 34 | + $this->output( sprintf( "%10s %20s %3d %s\n", $ip, $host, $lag, $stars ) ); |
| 35 | + } |
24 | 36 | } |
25 | | - $starLen = min( intval( $lag ), 40 ); |
26 | | - $stars = str_repeat( '*', $starLen ); |
27 | | - printf( "%10s %20s %3d %s\n", $ip, $host, $lag, $stars ); |
28 | 37 | } |
29 | 38 | } |
30 | 39 | |
| 40 | +$maintClass = "GetLagTimes"; |
| 41 | +require_once( DO_MAINTENANCE ); |
Index: branches/maintenance-work/maintenance/removeUnusedAccounts.php |
— | — | @@ -8,63 +8,89 @@ |
9 | 9 | * @author Rob Church <robchur@gmail.com> |
10 | 10 | */ |
11 | 11 | |
12 | | -$options = array( 'help', 'delete' ); |
13 | | -require_once( 'commandLine.inc' ); |
14 | | -require_once( 'removeUnusedAccounts.inc' ); |
15 | | -echo( "Remove Unused Accounts\n\n" ); |
16 | | -$fname = 'removeUnusedAccounts'; |
| 12 | +require_once( "Maintenance.php" ); |
17 | 13 | |
18 | | -if( isset( $options['help'] ) ) { |
19 | | - showHelp(); |
20 | | - exit(1); |
21 | | -} |
| 14 | +class RemoveUnusedAccounts extends Maintenance { |
| 15 | + public function __construct() { |
| 16 | + parent::__construct(); |
| 17 | + $this->addParam( 'delete', 'Actually delete the account' ); |
| 18 | + $this->addParam( 'ignore-groups', 'List of comma-separated groups to exclude', false, true ); |
| 19 | + $this->addParam( 'ignore-touched', 'Skip accounts touched in last N days', false, true ); |
| 20 | + } |
22 | 21 | |
23 | | -# Do an initial scan for inactive accounts and report the result |
24 | | -echo( "Checking for unused user accounts...\n" ); |
25 | | -$del = array(); |
26 | | -$dbr = wfGetDB( DB_SLAVE ); |
27 | | -$res = $dbr->select( 'user', array( 'user_id', 'user_name', 'user_touched' ), '', $fname ); |
28 | | -if( isset( $options['ignore-groups'] ) ) { |
29 | | - $excludedGroups = explode( ',', $options['ignore-groups'] ); |
30 | | -} else { $excludedGroups = array(); } |
31 | | -$touchedSeconds = 0; |
32 | | -if( isset( $options['ignore-touched'] ) ) { |
33 | | - $touchedParamError = 0; |
34 | | - if( ctype_digit( $options['ignore-touched'] ) ) { |
35 | | - if( $options['ignore-touched'] <= 0 ) { |
36 | | - $touchedParamError = 1; |
| 22 | + public function execute() { |
| 23 | + |
| 24 | + $this->output( "Remove unused accounts\n\n" ); |
| 25 | + |
| 26 | + # Do an initial scan for inactive accounts and report the result |
| 27 | + $this->output( "Checking for unused user accounts...\n" ); |
| 28 | + $del = array(); |
| 29 | + $dbr = wfGetDB( DB_SLAVE ); |
| 30 | + $res = $dbr->select( 'user', array( 'user_id', 'user_name', 'user_touched' ), '', __METHOD__ ); |
| 31 | + if( $this->hasOption('ignore-groups') ) { |
| 32 | + $excludedGroups = explode( ',', $this->getOption('ignore-groups') ); |
| 33 | + } else { |
| 34 | + $excludedGroups = array(); |
37 | 35 | } |
38 | | - } else { $touchedParamError = 1; } |
39 | | - if( $touchedParamError == 1 ) { |
40 | | - die( "Please put a valid positive integer on the --ignore-touched parameter.\n" ); |
41 | | - } else { $touchedSeconds = 86400 * $options['ignore-touched']; } |
42 | | -} |
43 | | -while( $row = $dbr->fetchObject( $res ) ) { |
44 | | - # Check the account, but ignore it if it's within a $excludedGroups group or if it's touched within the $touchedSeconds seconds. |
45 | | - $instance = User::newFromId( $row->user_id ); |
46 | | - if( count( array_intersect( $instance->getEffectiveGroups(), $excludedGroups ) ) == 0 |
47 | | - && isInactiveAccount( $row->user_id, true ) |
48 | | - && wfTimestamp( TS_UNIX, $row->user_touched ) < wfTimestamp( TS_UNIX, time() - $touchedSeconds ) |
49 | | - ) { |
50 | | - # Inactive; print out the name and flag it |
51 | | - $del[] = $row->user_id; |
52 | | - echo( $row->user_name . "\n" ); |
| 36 | + $touched = $this->getOption( 'ignore-touched', "1" ); |
| 37 | + if( !ctype_digit( $touched ) ) { |
| 38 | + $this->error( "Please put a valid positive integer on the --ignore-touched parameter.\n", true ); |
| 39 | + } |
| 40 | + $touchedSeconds = 86400 * $touched; |
| 41 | + while( $row = $dbr->fetchObject( $res ) ) { |
| 42 | + # Check the account, but ignore it if it's within a $excludedGroups group or if it's touched within the $touchedSeconds seconds. |
| 43 | + $instance = User::newFromId( $row->user_id ); |
| 44 | + if( count( array_intersect( $instance->getEffectiveGroups(), $excludedGroups ) ) == 0 |
| 45 | + && $this->isInactiveAccount( $row->user_id, true ) |
| 46 | + && wfTimestamp( TS_UNIX, $row->user_touched ) < wfTimestamp( TS_UNIX, time() - $touchedSeconds ) |
| 47 | + ) { |
| 48 | + # Inactive; print out the name and flag it |
| 49 | + $del[] = $row->user_id; |
| 50 | + $this->output( $row->user_name . "\n" ); |
| 51 | + } |
| 52 | + } |
| 53 | + $count = count( $del ); |
| 54 | + $this->output( "...found {$count}.\n" ); |
| 55 | + |
| 56 | + # If required, go back and delete each marked account |
| 57 | + if( $count > 0 && $this->hasOption('delete') ) { |
| 58 | + $this->output( "\nDeleting inactive accounts..." ); |
| 59 | + $dbw = wfGetDB( DB_MASTER ); |
| 60 | + $dbw->delete( 'user', array( 'user_id' => $del ), __METHOD__ ); |
| 61 | + $this->output( "done.\n" ); |
| 62 | + # Update the site_stats.ss_users field |
| 63 | + $users = $dbw->selectField( 'user', 'COUNT(*)', array(), __METHOD__ ); |
| 64 | + $dbw->update( 'site_stats', array( 'ss_users' => $users ), array( 'ss_row_id' => 1 ), __METHOD__ ); |
| 65 | + } elseif( $count > 0 ) { |
| 66 | + $this->output( "\nRun the script again with --delete to remove them from the database.\n" ); |
| 67 | + } |
| 68 | + $this->output( "\n" ); |
53 | 69 | } |
| 70 | + |
| 71 | + /** |
| 72 | + * Could the specified user account be deemed inactive? |
| 73 | + * (No edits, no deleted edits, no log entries, no current/old uploads) |
| 74 | + * |
| 75 | + * @param $id User's ID |
| 76 | + * @param $master Perform checking on the master |
| 77 | + * @return bool |
| 78 | + */ |
| 79 | + private function isInactiveAccount( $id, $master = false ) { |
| 80 | + $dbo = wfGetDB( $master ? DB_MASTER : DB_SLAVE ); |
| 81 | + $checks = array( 'revision' => 'rev', 'archive' => 'ar', 'logging' => 'log', |
| 82 | + 'image' => 'img', 'oldimage' => 'oi' ); |
| 83 | + $count = 0; |
| 84 | + |
| 85 | + $dbo->immediateBegin(); |
| 86 | + foreach( $checks as $table => $fprefix ) { |
| 87 | + $conds = array( $fprefix . '_user' => $id ); |
| 88 | + $count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, __METHOD__ ); |
| 89 | + } |
| 90 | + $dbo->immediateCommit(); |
| 91 | + |
| 92 | + return $count == 0; |
| 93 | + } |
54 | 94 | } |
55 | | -$count = count( $del ); |
56 | | -echo( "...found {$count}.\n" ); |
57 | 95 | |
58 | | -# If required, go back and delete each marked account |
59 | | -if( $count > 0 && isset( $options['delete'] ) ) { |
60 | | - echo( "\nDeleting inactive accounts..." ); |
61 | | - $dbw = wfGetDB( DB_MASTER ); |
62 | | - $dbw->delete( 'user', array( 'user_id' => $del ), $fname ); |
63 | | - echo( "done.\n" ); |
64 | | - # Update the site_stats.ss_users field |
65 | | - $users = $dbw->selectField( 'user', 'COUNT(*)', array(), $fname ); |
66 | | - $dbw->update( 'site_stats', array( 'ss_users' => $users ), array( 'ss_row_id' => 1 ), $fname ); |
67 | | -} else { |
68 | | - if( $count > 0 ) |
69 | | - echo( "\nRun the script again with --delete to remove them from the database.\n" ); |
70 | | -} |
71 | | -echo( "\n" ); |
| 96 | +$maintClass = "RemoveUnusedAccounts"; |
| 97 | +require_once( DO_MAINTENANCE ); |
Index: branches/maintenance-work/maintenance/populateParentId.php |
— | — | @@ -1,18 +1,105 @@ |
2 | 2 | <?php |
3 | | - |
4 | 3 | /* |
5 | 4 | * Makes the required database updates for rev_parent_id |
6 | 5 | * to be of any use. It can be used for some simple tracking |
7 | 6 | * and to find new page edits by users. |
8 | 7 | */ |
9 | 8 | |
10 | | -require_once 'commandLine.inc'; |
11 | | -require_once 'populateParentId.inc'; |
12 | | - |
13 | | -$db =& wfGetDB( DB_MASTER ); |
14 | | -if ( !$db->tableExists( 'revision' ) ) { |
15 | | - echo "revision table does not exist\n"; |
16 | | - exit( 1 ); |
| 9 | +require_once( "Maintenance.php" ); |
| 10 | + |
| 11 | +class PopulateParentId extends Maintenance { |
| 12 | + |
| 13 | + // Batch size |
| 14 | + const BATCH_SIZE = 200; |
| 15 | + |
| 16 | + public function __construct() { |
| 17 | + parent::__construct(); |
| 18 | + $this->mDescription = "Populates rev_parent_id"; |
| 19 | + } |
| 20 | + |
| 21 | + public function execute() { |
| 22 | + $db = wfGetDB( DB_MASTER ); |
| 23 | + if ( !$db->tableExists( 'revision' ) ) { |
| 24 | + $this->error( "revision table does not exist\n", true ); |
| 25 | + } |
| 26 | + $this->output( "Populating rev_parent_id column\n" ); |
| 27 | + $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __FUNCTION__ ); |
| 28 | + $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ ); |
| 29 | + if( is_null( $start ) || is_null( $end ) ){ |
| 30 | + $this->output( "...revision table seems to be empty.\n" ); |
| 31 | + $db->insert( 'updatelog', |
| 32 | + array( 'ul_key' => 'populate rev_parent_id' ), |
| 33 | + __FUNCTION__, |
| 34 | + 'IGNORE' ); |
| 35 | + return; |
| 36 | + } |
| 37 | + # Do remaining chunk |
| 38 | + $end += self::BATCH_SIZE - 1; |
| 39 | + $blockStart = intval( $start ); |
| 40 | + $blockEnd = intval( $start ) + self::BATCH_SIZE - 1; |
| 41 | + $count = 0; |
| 42 | + $changed = 0; |
| 43 | + while( $blockEnd <= $end ) { |
| 44 | + $this->output( "...doing rev_id from $blockStart to $blockEnd\n" ); |
| 45 | + $cond = "rev_id BETWEEN $blockStart AND $blockEnd"; |
| 46 | + $res = $db->select( 'revision', |
| 47 | + array('rev_id','rev_page','rev_timestamp','rev_parent_id'), |
| 48 | + $cond, __FUNCTION__ ); |
| 49 | + # Go through and update rev_parent_id from these rows. |
| 50 | + # Assume that the previous revision of the title was |
| 51 | + # the original previous revision of the title when the |
| 52 | + # edit was made... |
| 53 | + foreach( $res as $row ) { |
| 54 | + # First, check rows with the same timestamp other than this one |
| 55 | + # with a smaller rev ID. The highest ID "wins". This avoids loops |
| 56 | + # as timestamp can only decrease and never loops with IDs (from parent to parent) |
| 57 | + $previousID = $db->selectField( 'revision', 'rev_id', |
| 58 | + array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $row->rev_timestamp, |
| 59 | + "rev_id < " . intval( $row->rev_id ) ), |
| 60 | + __FUNCTION__, |
| 61 | + array( 'ORDER BY' => 'rev_id DESC' ) ); |
| 62 | + # If there are none, check the the highest ID with a lower timestamp |
| 63 | + if( !$previousID ) { |
| 64 | + # Get the highest older timestamp |
| 65 | + $lastTimestamp = $db->selectField( 'revision', 'rev_timestamp', |
| 66 | + array( 'rev_page' => $row->rev_page, "rev_timestamp < " . $db->addQuotes( $row->rev_timestamp ) ), |
| 67 | + __FUNCTION__, |
| 68 | + array( 'ORDER BY' => 'rev_timestamp DESC' ) ); |
| 69 | + # If there is one, let the highest rev ID win |
| 70 | + if( $lastTimestamp ) { |
| 71 | + $previousID = $db->selectField( 'revision', 'rev_id', |
| 72 | + array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $lastTimestamp ), |
| 73 | + __FUNCTION__, |
| 74 | + array( 'ORDER BY' => 'rev_id DESC' ) ); |
| 75 | + } |
| 76 | + } |
| 77 | + $previousID = intval($previousID); |
| 78 | + if( $previousID != $row->rev_parent_id ) |
| 79 | + $changed++; |
| 80 | + # Update the row... |
| 81 | + $db->update( 'revision', |
| 82 | + array( 'rev_parent_id' => $previousID ), |
| 83 | + array( 'rev_id' => $row->rev_id ), |
| 84 | + __FUNCTION__ ); |
| 85 | + $count++; |
| 86 | + } |
| 87 | + $blockStart += self::BATCH_SIZE - 1; |
| 88 | + $blockEnd += self::BATCH_SIZE - 1; |
| 89 | + wfWaitForSlaves( 5 ); |
| 90 | + } |
| 91 | + $logged = $db->insert( 'updatelog', |
| 92 | + array( 'ul_key' => 'populate rev_parent_id' ), |
| 93 | + __FUNCTION__, |
| 94 | + 'IGNORE' ); |
| 95 | + if( $logged ) { |
| 96 | + $this->output( "rev_parent_id population complete ... {$count} rows [{$changed} changed]\n" ); |
| 97 | + return true; |
| 98 | + } else { |
| 99 | + $this->output( "Could not insert rev_parent_id population row.\n" ); |
| 100 | + return false; |
| 101 | + } |
| 102 | + } |
17 | 103 | } |
18 | 104 | |
19 | | -populate_rev_parent_id( $db ); |
| 105 | +$maintClass = "PopulateParentId"; |
| 106 | +require_once( DO_MAINTENANCE ); |
Index: branches/maintenance-work/maintenance/createAndPromote.php |
— | — | @@ -20,11 +20,8 @@ |
21 | 21 | } |
22 | 22 | |
23 | 23 | public function execute() { |
24 | | - if( count( $this->mArgs ) < 2 ) { |
25 | | - $this->error( "Please provide a username and password for the new account.\n", true ); |
26 | | - } |
27 | | - $username = $this->mArgs[0]; |
28 | | - $password = $this->mArgs[1]; |
| 24 | + $username = $this->getArg(0); |
| 25 | + $password = $this->getArg(1); |
29 | 26 | |
30 | 27 | $this->output( wfWikiID() . ": Creating and promoting User:{$username}..." ); |
31 | 28 | |
Index: branches/maintenance-work/maintenance/fetchText.php |
— | — | @@ -6,34 +6,48 @@ |
7 | 7 | * @ingroup Maintenance |
8 | 8 | */ |
9 | 9 | |
10 | | -require "commandLine.inc"; |
| 10 | +require_once( "Maintenance.php" ); |
11 | 11 | |
12 | | -$db = wfGetDB( DB_SLAVE ); |
13 | | -$stdin = fopen( "php://stdin", "rt" ); |
14 | | -while( !feof( $stdin ) ) { |
15 | | - $line = fgets( $stdin ); |
16 | | - if( $line === false ) { |
17 | | - // We appear to have lost contact... |
18 | | - break; |
| 12 | +class FetchText extends Maintenance { |
| 13 | + public function __construct() { |
| 14 | + parent::__construct(); |
| 15 | + $this->mDescription = "Fetch the revision text from an old_id"; |
19 | 16 | } |
20 | | - $textId = intval( $line ); |
21 | | - $text = doGetText( $db, $textId ); |
22 | | - echo strlen( $text ) . "\n"; |
23 | | - echo $text; |
24 | | -} |
25 | 17 | |
26 | | -/** |
27 | | - * May throw a database error if, say, the server dies during query. |
28 | | - */ |
29 | | -function doGetText( $db, $id ) { |
30 | | - $id = intval( $id ); |
31 | | - $row = $db->selectRow( 'text', |
32 | | - array( 'old_text', 'old_flags' ), |
33 | | - array( 'old_id' => $id ), |
34 | | - 'TextPassDumper::getText' ); |
35 | | - $text = Revision::getRevisionText( $row ); |
36 | | - if( $text === false ) { |
37 | | - return false; |
| 18 | + public function execute() { |
| 19 | + $db = wfGetDB( DB_SLAVE ); |
| 20 | + $stdin = $this->getStdin(); |
| 21 | + while( !feof( $stdin ) ) { |
| 22 | + $line = fgets( $stdin ); |
| 23 | + if( $line === false ) { |
| 24 | + // We appear to have lost contact... |
| 25 | + break; |
| 26 | + } |
| 27 | + $textId = intval( $line ); |
| 28 | + $text = $this->doGetText( $db, $textId ); |
| 29 | + $this->output( strlen( $text ) . "\n". $text ); |
| 30 | + } |
38 | 31 | } |
39 | | - return $text; |
| 32 | + |
| 33 | + /** |
| 34 | + * May throw a database error if, say, the server dies during query. |
| 35 | + * @param $db Database object |
| 36 | + * @param $id int The old_id |
| 37 | + * @return String |
| 38 | + */ |
| 39 | + private function doGetText( $db, $id ) { |
| 40 | + $id = intval( $id ); |
| 41 | + $row = $db->selectRow( 'text', |
| 42 | + array( 'old_text', 'old_flags' ), |
| 43 | + array( 'old_id' => $id ), |
| 44 | + 'TextPassDumper::getText' ); |
| 45 | + $text = Revision::getRevisionText( $row ); |
| 46 | + if( $text === false ) { |
| 47 | + return false; |
| 48 | + } |
| 49 | + return $text; |
| 50 | + } |
40 | 51 | } |
| 52 | + |
| 53 | +$maintClass = "FetchText"; |
| 54 | +require_once( DO_MAINTENANCE ); |