r52509 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r52508‎ | r52509 | r52510 >
Date:14:17, 28 June 2009
Author:demon
Status:deferred
Tags:
Comment:
* Port edit, initEditCount, purgeList, cleanupSpam, convertLinks, fixUserRegistration, DumpUploads
* Add description for updateRestrictions
* Fix stupid mistake in rebuildFileCache
* Spacing above description in help
Modified paths:
  • /branches/maintenance-work/maintenance/Maintenance.php (modified) (history)
  • /branches/maintenance-work/maintenance/cleanupSpam.php (modified) (history)
  • /branches/maintenance-work/maintenance/convertLinks.inc (deleted) (history)
  • /branches/maintenance-work/maintenance/convertLinks.php (modified) (history)
  • /branches/maintenance-work/maintenance/dumpUploads.php (modified) (history)
  • /branches/maintenance-work/maintenance/edit.php (modified) (history)
  • /branches/maintenance-work/maintenance/fixUserRegistration.php (modified) (history)
  • /branches/maintenance-work/maintenance/initEditCount.php (modified) (history)
  • /branches/maintenance-work/maintenance/purgeList.php (modified) (history)
  • /branches/maintenance-work/maintenance/rebuildFileCache.php (modified) (history)
  • /branches/maintenance-work/maintenance/updateRestrictions.php (modified) (history)

Diff [purge]

Index: branches/maintenance-work/maintenance/convertLinks.inc
@@ -1,216 +0,0 @@
2 -<?php
3 -/**
4 - * @file
5 - * @todo document
6 - * @ingroup Maintenance
7 - */
8 -
9 -/** */
10 -function convertLinks() {
11 - global $wgDBtype;
12 - if( $wgDBtype == 'postgres' ) {
13 - wfOut( "Links table already ok on Postgres.\n" );
14 - return;
15 - }
16 -
17 - wfOut( "Converting links table to ID-ID...\n" );
18 -
19 - global $wgLang, $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
20 - global $noKeys, $logPerformance, $fh;
21 -
22 - $tuplesAdded = $numBadLinks = $curRowsRead = 0; #counters etc
23 - $totalTuplesInserted = 0; # total tuples INSERTed into links_temp
24 -
25 - $reportCurReadProgress = true; #whether or not to give progress reports while reading IDs from cur table
26 - $curReadReportInterval = 1000; #number of rows between progress reports
27 -
28 - $reportLinksConvProgress = true; #whether or not to give progress reports during conversion
29 - $linksConvInsertInterval = 1000; #number of rows per INSERT
30 -
31 - $initialRowOffset = 0;
32 - #$finalRowOffset = 0; # not used yet; highest row number from links table to process
33 -
34 - # Overwrite the old links table with the new one. If this is set to false,
35 - # the new table will be left at links_temp.
36 - $overwriteLinksTable = true;
37 -
38 - # Don't create keys, and so allow duplicates in the new links table.
39 - # This gives a huge speed improvement for very large links tables which are MyISAM. (What about InnoDB?)
40 - $noKeys = false;
41 -
42 -
43 - $logPerformance = false; # output performance data to a file
44 - $perfLogFilename = "convLinksPerf.txt";
45 - #--------------------------------------------------------------------
46 -
47 - $dbw = wfGetDB( DB_MASTER );
48 - list ($cur, $links, $links_temp, $links_backup) = $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' );
49 -
50 - $res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
51 - if ( $dbw->fieldType( $res, 0 ) == "int" ) {
52 - wfOut( "Schema already converted\n" );
53 - return;
54 - }
55 -
56 - $res = $dbw->query( "SELECT COUNT(*) AS count FROM $links" );
57 - $row = $dbw->fetchObject($res);
58 - $numRows = $row->count;
59 - $dbw->freeResult( $res );
60 -
61 - if ( $numRows == 0 ) {
62 - wfOut( "Updating schema (no rows to convert)...\n" );
63 - createTempTable();
64 - } else {
65 - if ( $logPerformance ) { $fh = fopen ( $perfLogFilename, "w" ); }
66 - $baseTime = $startTime = getMicroTime();
67 - # Create a title -> cur_id map
68 - wfOut( "Loading IDs from $cur table...\n" );
69 - performanceLog ( "Reading $numRows rows from cur table...\n" );
70 - performanceLog ( "rows read vs seconds elapsed:\n" );
71 -
72 - $dbw->bufferResults( false );
73 - $res = $dbw->query( "SELECT cur_namespace,cur_title,cur_id FROM $cur" );
74 - $ids = array();
75 -
76 - while ( $row = $dbw->fetchObject( $res ) ) {
77 - $title = $row->cur_title;
78 - if ( $row->cur_namespace ) {
79 - $title = $wgLang->getNsText( $row->cur_namespace ) . ":$title";
80 - }
81 - $ids[$title] = $row->cur_id;
82 - $curRowsRead++;
83 - if ($reportCurReadProgress) {
84 - if (($curRowsRead % $curReadReportInterval) == 0) {
85 - performanceLog( $curRowsRead . " " . (getMicroTime() - $baseTime) . "\n" );
86 - wfOut( "\t$curRowsRead rows of $cur table read.\n" );
87 - }
88 - }
89 - }
90 - $dbw->freeResult( $res );
91 - $dbw->bufferResults( true );
92 - wfOut( "Finished loading IDs.\n\n" );
93 - performanceLog( "Took " . (getMicroTime() - $baseTime) . " seconds to load IDs.\n\n" );
94 - #--------------------------------------------------------------------
95 -
96 - # Now, step through the links table (in chunks of $linksConvInsertInterval rows),
97 - # convert, and write to the new table.
98 - createTempTable();
99 - performanceLog( "Resetting timer.\n\n" );
100 - $baseTime = getMicroTime();
101 - wfOut( "Processing $numRows rows from $links table...\n" );
102 - performanceLog( "Processing $numRows rows from $links table...\n" );
103 - performanceLog( "rows inserted vs seconds elapsed:\n" );
104 -
105 - for ($rowOffset = $initialRowOffset; $rowOffset < $numRows; $rowOffset += $linksConvInsertInterval) {
106 - $sqlRead = "SELECT * FROM $links ";
107 - $sqlRead = $dbw->limitResult($sqlRead, $linksConvInsertInterval,$rowOffset);
108 - $res = $dbw->query($sqlRead);
109 - if ( $noKeys ) {
110 - $sqlWrite = array("INSERT INTO $links_temp (l_from,l_to) VALUES ");
111 - } else {
112 - $sqlWrite = array("INSERT IGNORE INTO $links_temp (l_from,l_to) VALUES ");
113 - }
114 -
115 - $tuplesAdded = 0; # no tuples added to INSERT yet
116 - while ( $row = $dbw->fetchObject($res) ) {
117 - $fromTitle = $row->l_from;
118 - if ( array_key_exists( $fromTitle, $ids ) ) { # valid title
119 - $from = $ids[$fromTitle];
120 - $to = $row->l_to;
121 - if ( $tuplesAdded != 0 ) {
122 - $sqlWrite[] = ",";
123 - }
124 - $sqlWrite[] = "($from,$to)";
125 - $tuplesAdded++;
126 - } else { # invalid title
127 - $numBadLinks++;
128 - }
129 - }
130 - $dbw->freeResult($res);
131 - #wfOut( "rowOffset: $rowOffset\ttuplesAdded: $tuplesAdded\tnumBadLinks: $numBadLinks\n" );
132 - if ( $tuplesAdded != 0 ) {
133 - if ($reportLinksConvProgress) {
134 - wfOut( "Inserting $tuplesAdded tuples into $links_temp..." );
135 - }
136 - $dbw->query( implode("",$sqlWrite) );
137 - $totalTuplesInserted += $tuplesAdded;
138 - if ($reportLinksConvProgress)
139 - wfOut( " done. Total $totalTuplesInserted tuples inserted.\n" );
140 - performanceLog( $totalTuplesInserted . " " . (getMicroTime() - $baseTime) . "\n" );
141 - }
142 - }
143 - wfOut( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n\n" );
144 - performanceLog( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n" );
145 - performanceLog( "Total execution time: " . (getMicroTime() - $startTime) . " seconds.\n" );
146 - if ( $logPerformance ) { fclose ( $fh ); }
147 - }
148 - #--------------------------------------------------------------------
149 -
150 - if ( $overwriteLinksTable ) {
151 - $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
152 - if (!($dbConn->isOpen())) {
153 - wfOut( "Opening connection to database failed.\n" );
154 - return;
155 - }
156 - # Check for existing links_backup, and delete it if it exists.
157 - wfOut( "Dropping backup links table if it exists..." );
158 - $dbConn->query( "DROP TABLE IF EXISTS $links_backup", DB_MASTER);
159 - wfOut( " done.\n" );
160 -
161 - # Swap in the new table, and move old links table to links_backup
162 - wfOut( "Swapping tables '$links' to '$links_backup'; '$links_temp' to '$links'..." );
163 - $dbConn->query( "RENAME TABLE links TO $links_backup, $links_temp TO $links", DB_MASTER );
164 - wfOut( " done.\n\n" );
165 -
166 - $dbConn->close();
167 - wfOut( "Conversion complete. The old table remains at $links_backup;\n" );
168 - wfOut( "delete at your leisure.\n" );
169 - } else {
170 - wfOut( "Conversion complete. The converted table is at $links_temp;\n" );
171 - wfOut( "the original links table is unchanged.\n" );
172 - }
173 -}
174 -
175 -#--------------------------------------------------------------------
176 -
177 -function createTempTable() {
178 - global $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
179 - global $noKeys;
180 - $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
181 -
182 - if (!($dbConn->isOpen())) {
183 - wfOut( "Opening connection to database failed.\n" );
184 - return;
185 - }
186 - $links_temp = $dbConn->tableName( 'links_temp' );
187 -
188 - wfOut( "Dropping temporary links table if it exists..." );
189 - $dbConn->query( "DROP TABLE IF EXISTS $links_temp");
190 - wfOut( " done.\n" );
191 -
192 - wfOut( "Creating temporary links table..." );
193 - if ( $noKeys ) {
194 - $dbConn->query( "CREATE TABLE $links_temp ( " .
195 - "l_from int(8) unsigned NOT NULL default '0', " .
196 - "l_to int(8) unsigned NOT NULL default '0')");
197 - } else {
198 - $dbConn->query( "CREATE TABLE $links_temp ( " .
199 - "l_from int(8) unsigned NOT NULL default '0', " .
200 - "l_to int(8) unsigned NOT NULL default '0', " .
201 - "UNIQUE KEY l_from(l_from,l_to), " .
202 - "KEY (l_to))");
203 - }
204 - wfOut( " done.\n\n" );
205 -}
206 -
207 -function performanceLog( $text ) {
208 - global $logPerformance, $fh;
209 - if ( $logPerformance ) {
210 - fwrite( $fh, $text );
211 - }
212 -}
213 -
214 -function getMicroTime() { # return time in seconds, with microsecond accuracy
215 - list($usec, $sec) = explode(" ", microtime());
216 - return ((float)$usec + (float)$sec);
217 -}
Index: branches/maintenance-work/maintenance/dumpUploads.php
@@ -4,34 +4,36 @@
55 * @ingroup Maintenance
66 */
77
8 -require_once 'commandLine.inc';
 8+require_once( "Maintenance.php" );
99
10 -class UploadDumper {
11 - function __construct( $args ) {
 10+class UploadDumper extends Maintenance {
 11+ public function __construct() {
 12+ parent::__construct();
 13+ $this->mDescription = "Generates list of uploaded files which can be fed to tar or similar.
 14+By default, outputs relative paths against the parent directory of \$wgUploadDirectory.";
 15+ $this->addOption( 'base', 'Set base relative path instead of wiki include root', false, true );
 16+ $this->addOption( 'local', 'List all local files, used or not. No shared files included' );
 17+ $this->addOption( 'used', 'Skip local images that are not used' );
 18+ $this->addOption( 'shared', 'Include images used from shared repository' );
 19+ }
 20+
 21+ public function execute() {
1222 global $IP, $wgUseSharedUploads;
1323 $this->mAction = 'fetchLocal';
14 - $this->mBasePath = $IP;
 24+ $this->mBasePath = $this->getOption( 'base', $IP );
1525 $this->mShared = false;
1626 $this->mSharedSupplement = false;
17 -
18 - if( isset( $args['help'] ) ) {
19 - $this->mAction = 'help';
20 - }
21 -
22 - if( isset( $args['base'] ) ) {
23 - $this->mBasePath = $args['base'];
24 - }
25 -
26 - if( isset( $args['local'] ) ) {
 27+
 28+ if( $this->hasOption('local') ) {
2729 $this->mAction = 'fetchLocal';
2830 }
2931
30 - if( isset( $args['used'] ) ) {
 32+ if( $this->hasOption('used') ) {
3133 $this->mAction = 'fetchUsed';
3234 }
3335
34 - if( isset( $args['shared'] ) ) {
35 - if( isset( $args['used'] ) ) {
 36+ if( $this->hasOption('shared') ) {
 37+ if( $this->hasOption('used') ) {
3638 // Include shared-repo files in the used check
3739 $this->mShared = true;
3840 } else {
@@ -39,34 +41,12 @@
4042 $this->mSharedSupplement = true;
4143 }
4244 }
43 - }
44 -
45 - function run() {
4645 $this->{$this->mAction}( $this->mShared );
4746 if( $this->mSharedSupplement ) {
4847 $this->fetchUsed( true );
4948 }
5049 }
51 -
52 - function help() {
53 - echo <<<END
54 -Generates list of uploaded files which can be fed to tar or similar.
55 -By default, outputs relative paths against the parent directory of
56 -\$wgUploadDirectory.
5750
58 -Usage:
59 -php dumpUploads.php [options] > list-o-files.txt
60 -
61 -Options:
62 -
63 -
64 -END;
65 - }
66 -
6751 /**
6852 * Fetch a list of all or used images from a particular image source.
6953 * @param string $table
@@ -89,7 +69,7 @@
9070 }
9171 $dbr->freeResult( $result );
9272 }
93 -
 73+
9474 function fetchLocal( $shared ) {
9575 $dbr = wfGetDB( DB_SLAVE );
9676 $result = $dbr->select( 'image',
@@ -108,17 +88,16 @@
10989 if( $file && $this->filterItem( $file, $shared ) ) {
11090 $filename = $file->getFullPath();
11191 $rel = wfRelativePath( $filename, $this->mBasePath );
112 - echo "$rel\n";
 92+ $this->output( "$rel\n" );
11393 } else {
11494 wfDebug( __METHOD__ . ": base file? $name\n" );
11595 }
11696 }
117 -
 97+
11898 function filterItem( $file, $shared ) {
11999 return $shared || $file->isLocal();
120100 }
121101 }
122102
123 -$dumper = new UploadDumper( $options );
124 -$dumper->run();
125 -
 103+$maintClass = "UploadDumper";
 104+require_once( DO_MAINTENANCE );
Index: branches/maintenance-work/maintenance/rebuildFileCache.php
@@ -98,4 +98,6 @@
9999 unset($wgArticle);
100100 }
101101 }
102 -require_once( "commandLine.inc" );
 102+
 103+$maintClass = "RebuildFileCache";
 104+require_once( DO_MAINTENANCE );
Index: branches/maintenance-work/maintenance/fixUserRegistration.php
@@ -7,28 +7,35 @@
88 * @ingroup Maintenance
99 */
1010
11 -require_once( 'commandLine.inc' );
 11+require_once( "Maintenance.php" );
1212
13 -$fname = 'fixUserRegistration.php';
 13+class FixUserRegistration extends Maintenance {
 14+ public function __construct() {
 15+ parent::__construct();
 16+ $this->mDescription = "Fix the user_registration field";
 17+ }
1418
15 -$dbr = wfGetDB( DB_SLAVE );
16 -$dbw = wfGetDB( DB_MASTER );
 19+ public function execute() {
 20+ $dbr = wfGetDB( DB_SLAVE );
 21+ $dbw = wfGetDB( DB_MASTER );
1722
18 -// Get user IDs which need fixing
19 -$res = $dbr->select( 'user', 'user_id', 'user_registration IS NULL', $fname );
20 -
21 -while ( $row = $dbr->fetchObject( $res ) ) {
22 - $id = $row->user_id;
23 - // Get first edit time
24 - $timestamp = $dbr->selectField( 'revision', 'MIN(rev_timestamp)', array( 'rev_user' => $id ), $fname );
25 - // Update
26 - if ( !empty( $timestamp ) ) {
27 - $dbw->update( 'user', array( 'user_registration' => $timestamp ), array( 'user_id' => $id ), $fname );
28 - print "$id $timestamp\n";
29 - } else {
30 - print "$id NULL\n";
 23+ // Get user IDs which need fixing
 24+ $res = $dbr->select( 'user', 'user_id', 'user_registration IS NULL', __METHOD__ );
 25+ while ( $row = $dbr->fetchObject( $res ) ) {
 26+ $id = $row->user_id;
 27+ // Get first edit time
 28+ $timestamp = $dbr->selectField( 'revision', 'MIN(rev_timestamp)', array( 'rev_user' => $id ), __METHOD__ );
 29+ // Update
 30+ if ( !empty( $timestamp ) ) {
 31+ $dbw->update( 'user', array( 'user_registration' => $timestamp ), array( 'user_id' => $id ), __METHOD__ );
 32+ $this->output( "$id $timestamp\n" );
 33+ } else {
 34+ $this->output( "$id NULL\n" );
 35+ }
 36+ }
 37+ $this->output( "\n" );
3138 }
3239 }
33 -print "\n";
3440
35 -
 41+$maintClass = "FixUserRegistration";
 42+require_once( DO_MAINTENANCE );
Index: branches/maintenance-work/maintenance/edit.php
@@ -4,74 +4,70 @@
55 * @ingroup Maintenance
66 */
77
8 -$optionsWithArgs = array( 'u', 's' );
 8+require_once( "Maintenance.php" );
99
10 -require_once( 'commandLine.inc' );
 10+class EditCLI extends Maintenance {
 11+ public function __construct() {
 12+ parent::__construct();
 13+ $this->mDescription = "Edit an article from the command line, text is from stdin";
 14+ $this->addOption( 'u', 'Username', false, true );
 15+ $this->addOption( 's', 'Edit summary', false, true );
 16+ $this->addOption( 'm', 'Minor edit' );
 17+ $this->addOption( 'b', 'Bot edit' );
 18+ $this->addOption( 'a', 'Enable autosummary' );
 19+ $this->addOption( 'no-rc', 'Do not show the change in recent changes' );
 20+ $this->addArgs( array( 'title' ) );
 21+ }
1122
12 -if ( count( $args ) == 0 || isset( $options['help'] ) ) {
13 - print <<<EOT
14 -Edit an article from the command line
 23+ public function execute() {
 24+ global $wgUser, $wgTitle, $wgArticle;
1525
16 -Usage: php edit.php [options...] <title>
17 -
18 -Options:
19 - -u <user> Username
20 - -s <summary> Edit summary
21 - -m Minor edit
22 - -b Bot (hidden) edit
23 - -a Enable autosummary
24 - --no-rc Do not show the change in recent changes
25 -
26 -If the specified user does not exist, it will be created.
27 -The text for the edit will be read from stdin.
28 -
29 -EOT;
30 - exit( 1 );
 26+ $userName = $this->getOption( 'u', 'Maintenance script' );
 27+ $summary = $this->getOption( 's', '' );
 28+ $minor = $this->hasOption( 'm' );
 29+ $bot = $this->hasOption( 'b' );
 30+ $autoSummary = $this->hasOption( 'a' );
 31+ $noRC = $this->hasOption( 'no-rc' );
 32+
 33+ $wgUser = User::newFromName( $userName );
 34+ if ( !$wgUser ) {
 35+ $this->error( "Invalid username\n", true );
 36+ }
 37+ if ( $wgUser->isAnon() ) {
 38+ $wgUser->addToDatabase();
 39+ }
 40+
 41+ $wgTitle = Title::newFromText( $this->getArg() );
 42+ if ( !$wgTitle ) {
 43+ $this->error( "Invalid title\n", true );
 44+ }
 45+
 46+ $wgArticle = new Article( $wgTitle );
 47+
 48+ # Read the text
 49+ $text = $this->getStdin();
 50+
 51+ # Do the edit
 52+ $this->output( "Saving... " );
 53+ $status = $wgArticle->doEdit( $text, $summary,
 54+ ( $minor ? EDIT_MINOR : 0 ) |
 55+ ( $bot ? EDIT_FORCE_BOT : 0 ) |
 56+ ( $autoSummary ? EDIT_AUTOSUMMARY : 0 ) |
 57+ ( $noRC ? EDIT_SUPPRESS_RC : 0 ) );
 58+ if ( $status->isOK() ) {
 59+ $this->output( "done\n" );
 60+ $exit = 0;
 61+ } else {
 62+ $this->output( "failed\n" );
 63+ $exit = 1;
 64+ }
 65+ if ( !$status->isGood() ) {
 66+ $this->output( $status->getWikiText() . "\n" );
 67+ }
 68+ exit( $exit );
 69+ }
3170 }
3271
33 -$userName = isset( $options['u'] ) ? $options['u'] : 'Maintenance script';
34 -$summary = isset( $options['s'] ) ? $options['s'] : '';
35 -$minor = isset( $options['m'] );
36 -$bot = isset( $options['b'] );
37 -$autoSummary = isset( $options['a'] );
38 -$noRC = isset( $options['no-rc'] );
 72+$maintClass = "EditCLI";
 73+require_once( DO_MAINTENANCE );
3974
40 -$wgUser = User::newFromName( $userName );
41 -if ( !$wgUser ) {
42 - print "Invalid username\n";
43 - exit( 1 );
44 -}
45 -if ( $wgUser->isAnon() ) {
46 - $wgUser->addToDatabase();
47 -}
48 -
49 -$wgTitle = Title::newFromText( $args[0] );
50 -if ( !$wgTitle ) {
51 - print "Invalid title\n";
52 - exit( 1 );
53 -}
54 -
55 -$wgArticle = new Article( $wgTitle );
56 -
57 -# Read the text
58 -$text = file_get_contents( 'php://stdin' );
59 -
60 -# Do the edit
61 -print "Saving... ";
62 -$status = $wgArticle->doEdit( $text, $summary,
63 - ( $minor ? EDIT_MINOR : 0 ) |
64 - ( $bot ? EDIT_FORCE_BOT : 0 ) |
65 - ( $autoSummary ? EDIT_AUTOSUMMARY : 0 ) |
66 - ( $noRC ? EDIT_SUPPRESS_RC : 0 ) );
67 -if ( $status->isOK() ) {
68 - print "done\n";
69 - $exit = 0;
70 -} else {
71 - print "failed\n";
72 - $exit = 1;
73 -}
74 -if ( !$status->isGood() ) {
75 - print $status->getWikiText() . "\n";
76 -}
77 -exit( $exit );
78 -
Index: branches/maintenance-work/maintenance/Maintenance.php
@@ -396,7 +396,7 @@
397397 # Short options
398398 for ( $p=1; $p<strlen( $arg ); $p++ ) {
399399 $option = $arg{$p};
400 - if ( isset( $this->mParams[$option]['withArg'] ) ) {
 400+ if ( $this->mParams[$option]['withArg'] ) {
401401 $param = next( $argv );
402402 if ( $param === false ) {
403403 $this->error( "$arg needs a value after it\n", true );
@@ -444,6 +444,8 @@
445445 $this->mDbPass = $this->getOption( 'dbpass' );
446446 if( $this->hasOption( 'quiet' ) )
447447 $this->mQuiet = true;
 448+ if( $this->hasOption( 'batch-size' ) )
 449+ $this->mBatchSize = $this->getOption( 'batch-size' );
448450 }
449451
450452 /**
@@ -454,7 +456,7 @@
455457 if( $this->hasOption('help') || in_array( 'help', $this->mArgs ) || $force ) {
456458 $this->mQuiet = false;
457459 if( $this->mDescription ) {
458 - $this->output( $this->mDescription . "\n" );
 460+ $this->output( "\n" . $this->mDescription . "\n" );
459461 }
460462 $this->output( "\nUsage: php " . $this->mSelf );
461463 if( $this->mParams ) {
Index: branches/maintenance-work/maintenance/cleanupSpam.php
@@ -1,114 +1,113 @@
22 <?php
33 /**
4 - * @file
 4+ * Cleanup all spam from a given hostname
55 * @ingroup Maintenance
66 */
77
8 -require_once( 'commandLine.inc' );
9 -require_once( "$IP/includes/LinkFilter.php" );
 8+require_once( "Maintenance.php" );
109
11 -function cleanupArticle( $id, $domain ) {
12 - $title = Title::newFromID( $id );
13 - if ( !$title ) {
14 - print "Internal error: no page for ID $id\n";
15 - return;
 10+class CleanupSpam extends Maintenance {
 11+ public function __construct() {
 12+ parent::__construct();
 13+ $this->mDescription = "Cleanup all spam from a given hostname";
 14+ $this->addOption( 'all', 'Check all wikis in $wgLocalDatabases' );
 15+ $this->addArgs( array( 'hostname' ) );
1616 }
1717
18 - print $title->getPrefixedDBkey() . " ...";
19 - $rev = Revision::newFromTitle( $title );
20 - $revId = $rev->getId();
21 - $currentRevId = $revId;
 18+ public function execute() {
 19+ global $wgLocalDatabases;
 20+
 21+ $username = wfMsg( 'spambot_username' );
 22+ $wgUser = User::newFromName( $username );
 23+ // Create the user if necessary
 24+ if ( !$wgUser->getId() ) {
 25+ $wgUser->addToDatabase();
 26+ }
 27+ $spec = $this->getArg();
 28+ $like = LinkFilter::makeLike( $spec );
 29+ if ( !$like ) {
 30+ $this->error( "Not a valid hostname specification: $spec\n", true );
 31+ }
 32+
 33+ $dbr = wfGetDB( DB_SLAVE );
2234
23 - while ( $rev && LinkFilter::matchEntry( $rev->getText() , $domain ) ) {
24 - # Revision::getPrevious can't be used in this way before MW 1.6 (Revision.php 1.26)
25 - #$rev = $rev->getPrevious();
26 - $revId = $title->getPreviousRevisionID( $revId );
27 - if ( $revId ) {
28 - $rev = Revision::newFromTitle( $title, $revId );
 35+ if ( $this->hasOption('all') ) {
 36+ // Clean up spam on all wikis
 37+ $dbr = wfGetDB( DB_SLAVE );
 38+ $this->output( "Finding spam on " . count($wgLocalDatabases) . " wikis\n" );
 39+ $found = false;
 40+ foreach ( $wgLocalDatabases as $db ) {
 41+ $count = $dbr->selectField( "`$db`.externallinks", 'COUNT(*)',
 42+ array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), __METHOD__ );
 43+ if ( $count ) {
 44+ $found = true;
 45+ passthru( "php cleanupSpam.php $db $spec | sed s/^/$db: /" );
 46+ }
 47+ }
 48+ if ( $found ) {
 49+ $this->output( "All done\n" );
 50+ } else {
 51+ $this->output( "None found\n" );
 52+ }
2953 } else {
30 - $rev = false;
 54+ // Clean up spam on this wiki
 55+ $res = $dbr->select( 'externallinks', array( 'DISTINCT el_from' ),
 56+ array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), __METHOD__ );
 57+ $count = $dbr->numRows( $res );
 58+ $this->output( "Found $count articles containing $spec\n" );
 59+ while ( $row = $dbr->fetchObject( $res ) ) {
 60+ $this->cleanupArticle( $row->el_from, $spec );
 61+ }
 62+ if ( $count ) {
 63+ $this->output( "Done\n" );
 64+ }
3165 }
3266 }
33 - if ( $revId == $currentRevId ) {
34 - // The regex didn't match the current article text
35 - // This happens e.g. when a link comes from a template rather than the page itself
36 - print "False match\n";
37 - } else {
38 - $dbw = wfGetDB( DB_MASTER );
39 - $dbw->immediateBegin();
40 - if ( !$rev ) {
41 - // Didn't find a non-spammy revision, blank the page
42 - print "blanking\n";
43 - $article = new Article( $title );
44 - $article->updateArticle( '', wfMsg( 'spam_blanking', $domain ),
45 - false, false );
4667
 68+ private function cleanupArticle( $id, $domain ) {
 69+ $title = Title::newFromID( $id );
 70+ if ( !$title ) {
 71+ $this->error( "Internal error: no page for ID $id\n" );
 72+ return;
 73+ }
 74+
 75+ $this->output( $title->getPrefixedDBkey() . " ..." );
 76+ $rev = Revision::newFromTitle( $title );
 77+ $revId = $rev->getId();
 78+ $currentRevId = $revId;
 79+
 80+ while ( $rev && LinkFilter::matchEntry( $rev->getText() , $domain ) ) {
 81+ # Revision::getPrevious can't be used in this way before MW 1.6 (Revision.php 1.26)
 82+ #$rev = $rev->getPrevious();
 83+ $revId = $title->getPreviousRevisionID( $revId );
 84+ if ( $revId ) {
 85+ $rev = Revision::newFromTitle( $title, $revId );
 86+ } else {
 87+ $rev = false;
 88+ }
 89+ }
 90+ if ( $revId == $currentRevId ) {
 91+ // The regex didn't match the current article text
 92+ // This happens e.g. when a link comes from a template rather than the page itself
 93+ $this->output( "False match\n" );
4794 } else {
48 - // Revert to this revision
49 - print "reverting\n";
50 - $article = new Article( $title );
51 - $article->updateArticle( $rev->getText(), wfMsg( 'spam_reverting', $domain ), false, false );
 95+ $dbw = wfGetDB( DB_MASTER );
 96+ $dbw->immediateBegin();
 97+ if ( !$rev ) {
 98+ // Didn't find a non-spammy revision, blank the page
 99+ $this->output( "blanking\n" );
 100+ $article = new Article( $title );
 101+ $article->updateArticle( '', wfMsg( 'spam_blanking', $domain ),
 102+ false, false );
 103+
 104+ } else {
 105+ // Revert to this revision
 106+ $this->output( "reverting\n" );
 107+ $article = new Article( $title );
 108+ $article->updateArticle( $rev->getText(), wfMsg( 'spam_reverting', $domain ), false, false );
 109+ }
 110+ $dbw->immediateCommit();
 111+ wfDoUpdates();
52112 }
53 - $dbw->immediateCommit();
54 - wfDoUpdates();
55113 }
56114 }
57 -//------------------------------------------------------------------------------
58 -
59 -
60 -
61 -
62 -$username = wfMsg( 'spambot_username' );
63 -$fname = $username;
64 -$wgUser = User::newFromName( $username );
65 -// Create the user if necessary
66 -if ( !$wgUser->getId() ) {
67 - $wgUser->addToDatabase();
68 -}
69 -
70 -if ( !isset( $args[0] ) ) {
71 - print "Usage: php cleanupSpam.php <hostname>\n";
72 - exit(1);
73 -}
74 -$spec = $args[0];
75 -$like = LinkFilter::makeLike( $spec );
76 -if ( !$like ) {
77 - print "Not a valid hostname specification: $spec\n";
78 - exit(1);
79 -}
80 -
81 -$dbr = wfGetDB( DB_SLAVE );
82 -
83 -if ( isset($options['all']) ) {
84 - // Clean up spam on all wikis
85 - $dbr = wfGetDB( DB_SLAVE );
86 - print "Finding spam on " . count($wgLocalDatabases) . " wikis\n";
87 - $found = false;
88 - foreach ( $wgLocalDatabases as $db ) {
89 - $count = $dbr->selectField( "`$db`.externallinks", 'COUNT(*)',
90 - array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), $fname );
91 - if ( $count ) {
92 - $found = true;
93 - passthru( "php cleanupSpam.php $db $spec | sed s/^/$db: /" );
94 - }
95 - }
96 - if ( $found ) {
97 - print "All done\n";
98 - } else {
99 - print "None found\n";
100 - }
101 -} else {
102 - // Clean up spam on this wiki
103 - $res = $dbr->select( 'externallinks', array( 'DISTINCT el_from' ),
104 - array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), $fname );
105 - $count = $dbr->numRows( $res );
106 - print "Found $count articles containing $spec\n";
107 - while ( $row = $dbr->fetchObject( $res ) ) {
108 - cleanupArticle( $row->el_from, $spec );
109 - }
110 - if ( $count ) {
111 - print "Done\n";
112 - }
113 -}
114 -
115 -
Index: branches/maintenance-work/maintenance/updateRestrictions.php
@@ -14,7 +14,7 @@
1515 class UpdateRestrictions extends Maintenance {
1616 public function __construct() {
1717 parent::__construct();
18 - $this->mDescription = "";
 18+ $this->mDescription = "Updates page_restrictions table from old page_restriction column";
1919 $this->setBatchSize( 100 );
2020 }
2121
Index: branches/maintenance-work/maintenance/purgeList.php
@@ -6,34 +6,42 @@
77 * @ingroup Maintenance
88 */
99
10 -require_once( "commandLine.inc" );
 10+require_once( "Maintenance.php" );
1111
12 -$stdin = fopen( "php://stdin", "rt" );
13 -$urls = array();
 12+class PurgeList extends Maintenance {
 13+ public function __construct() {
 14+ parent::__construct();
 15+ $this->mDescription = "Send purge requests for listed pages to squid";
 16+ }
1417
15 -while( !feof( $stdin ) ) {
16 - $page = trim( fgets( $stdin ) );
17 - if ( substr( $page, 0, 7 ) == 'http://' ) {
18 - $urls[] = $page;
19 - } elseif( $page !== '' ) {
20 - $title = Title::newFromText( $page );
21 - if( $title ) {
22 - $url = $title->getFullUrl();
23 - echo "$url\n";
24 - $urls[] = $url;
25 - if( isset( $options['purge'] ) ) {
26 - $title->invalidateCache();
 18+ public function execute() {
 19+ $stdin = $this->getStdin();
 20+ $urls = array();
 21+
 22+ while( !feof( $stdin ) ) {
 23+ $page = trim( fgets( $stdin ) );
 24+ if ( substr( $page, 0, 7 ) == 'http://' ) {
 25+ $urls[] = $page;
 26+ } elseif( $page !== '' ) {
 27+ $title = Title::newFromText( $page );
 28+ if( $title ) {
 29+ $url = $title->getFullUrl();
 30+ $this->output( "$url\n" );
 31+ $urls[] = $url;
 32+ if( isset( $options['purge'] ) ) {
 33+ $title->invalidateCache();
 34+ }
 35+ } else {
 36+ $this->output( "(Invalid title '$page')\n" );
 37+ }
2738 }
28 - } else {
29 - echo "(Invalid title '$page')\n";
3039 }
 40+
 41+ $this->output( "Purging " . count( $urls ) . " urls...\n" );
 42+ $u = new SquidUpdate( $urls );
 43+ $u->doUpdate();
 44+
 45+ $this->output( "Done!\n" );
3146 }
3247 }
3348
34 -echo "Purging " . count( $urls ) . " urls...\n";
35 -$u = new SquidUpdate( $urls );
36 -$u->doUpdate();
37 -
38 -echo "Done!\n";
39 -
40 -
Index: branches/maintenance-work/maintenance/initEditCount.php
@@ -4,86 +4,90 @@
55 * @ingroup Maintenance
66 */
77
8 -require_once "commandLine.inc";
 8+require_once( "Maintenance.php" );
99
10 -if( isset( $options['help'] ) ) {
11 - die( "Batch-recalculate user_editcount fields from the revision table.
12 -Options:
13 - --quick Force the update to be done in a single query.
14 - --background Force replication-friendly mode; may be inefficient but
15 - avoids locking tables or lagging slaves with large updates;
16 - calculates counts on a slave if possible.
 10+class InitEditCount extends Maintenance {
 11+ public function __construct() {
 12+ parent::__construct();
 13+ $this->addOption( 'quick', 'Force the update to be done in a single query' );
 14+ $this->addOption( 'background', 'Force replication-friendly mode; may be inefficient but
 15+ avoids locking tables or lagging slaves with large updates;
 16+ calculates counts on a slave if possible.
1717
1818 Background mode will be automatically used if the server is MySQL 4.0
1919 (which does not support subqueries) or if multiple servers are listed
20 -in \$wgDBservers, usually indicating a replication environment.
 20+in $wgDBservers, usually indicating a replication environment.' );
 21+ $this->mDescription = "Batch-recalculate user_editcount fields from the revision table";
 22+ }
2123
22 -");
23 -}
24 -$dbw = wfGetDB( DB_MASTER );
25 -$user = $dbw->tableName( 'user' );
26 -$revision = $dbw->tableName( 'revision' );
 24+ public function execute() {
 25+ $dbw = wfGetDB( DB_MASTER );
 26+ $user = $dbw->tableName( 'user' );
 27+ $revision = $dbw->tableName( 'revision' );
2728
28 -$dbver = $dbw->getServerVersion();
 29+ $dbver = $dbw->getServerVersion();
2930
30 -// Autodetect mode...
31 -$backgroundMode = count( $wgDBservers ) > 1 ||
32 - ($dbw instanceof DatabaseMySql && version_compare( $dbver, '4.1' ) < 0);
 31+ // Autodetect mode...
 32+ $backgroundMode = count( $wgDBservers ) > 1 ||
 33+ ($dbw instanceof DatabaseMySql && version_compare( $dbver, '4.1' ) < 0);
 34+
 35+ if( $this->hasOption('background') ) {
 36+ $backgroundMode = true;
 37+ } elseif( $this->hasOption('quick') ) {
 38+ $backgroundMode = false;
 39+ }
3340
34 -if( isset( $options['background'] ) ) {
35 - $backgroundMode = true;
36 -} elseif( isset( $options['quick'] ) ) {
37 - $backgroundMode = false;
38 -}
 41+ if( $backgroundMode ) {
 42+ $this->output( "Using replication-friendly background mode...\n" );
3943
40 -if( $backgroundMode ) {
41 - echo "Using replication-friendly background mode...\n";
42 -
43 - $dbr = wfGetDB( DB_SLAVE );
44 - $chunkSize = 100;
45 - $lastUser = $dbr->selectField( 'user', 'MAX(user_id)', '', __FUNCTION__ );
46 -
47 - $start = microtime( true );
48 - $migrated = 0;
49 - for( $min = 0; $min <= $lastUser; $min += $chunkSize ) {
50 - $max = $min + $chunkSize;
51 - $result = $dbr->query(
52 - "SELECT
53 - user_id,
54 - COUNT(rev_user) AS user_editcount
55 - FROM $user
56 - LEFT OUTER JOIN $revision ON user_id=rev_user
57 - WHERE user_id > $min AND user_id <= $max
58 - GROUP BY user_id",
59 - __FUNCTION__ );
60 -
61 - while( $row = $dbr->fetchObject( $result ) ) {
62 - $dbw->update( 'user',
63 - array( 'user_editcount' => $row->user_editcount ),
64 - array( 'user_id' => $row->user_id ),
65 - __FUNCTION__ );
66 - ++$migrated;
 44+ $dbr = wfGetDB( DB_SLAVE );
 45+ $chunkSize = 100;
 46+ $lastUser = $dbr->selectField( 'user', 'MAX(user_id)', '', __METHOD__ );
 47+
 48+ $start = microtime( true );
 49+ $migrated = 0;
 50+ for( $min = 0; $min <= $lastUser; $min += $chunkSize ) {
 51+ $max = $min + $chunkSize;
 52+ $result = $dbr->query(
 53+ "SELECT
 54+ user_id,
 55+ COUNT(rev_user) AS user_editcount
 56+ FROM $user
 57+ LEFT OUTER JOIN $revision ON user_id=rev_user
 58+ WHERE user_id > $min AND user_id <= $max
 59+ GROUP BY user_id",
 60+ __METHOD__ );
 61+
 62+ while( $row = $dbr->fetchObject( $result ) ) {
 63+ $dbw->update( 'user',
 64+ array( 'user_editcount' => $row->user_editcount ),
 65+ array( 'user_id' => $row->user_id ),
 66+ __METHOD__ );
 67+ ++$migrated;
 68+ }
 69+ $dbr->freeResult( $result );
 70+
 71+ $delta = microtime( true ) - $start;
 72+ $rate = ($delta == 0.0) ? 0.0 : $migrated / $delta;
 73+ $this->output( sprintf( "%s %d (%0.1f%%) done in %0.1f secs (%0.3f accounts/sec).\n",
 74+ $wgDBname,
 75+ $migrated,
 76+ min( $max, $lastUser ) / $lastUser * 100.0,
 77+ $delta,
 78+ $rate ) );
 79+
 80+ wfWaitForSlaves( 10 );
 81+ }
 82+ } else {
 83+ // Subselect should work on modern MySQLs etc
 84+ $this->output( "Using single-query mode...\n" );
 85+ $sql = "UPDATE $user SET user_editcount=(SELECT COUNT(*) FROM $revision WHERE rev_user=user_id)";
 86+ $dbw->query( $sql );
6787 }
68 - $dbr->freeResult( $result );
69 -
70 - $delta = microtime( true ) - $start;
71 - $rate = ($delta == 0.0) ? 0.0 : $migrated / $delta;
72 - printf( "%s %d (%0.1f%%) done in %0.1f secs (%0.3f accounts/sec).\n",
73 - $wgDBname,
74 - $migrated,
75 - min( $max, $lastUser ) / $lastUser * 100.0,
76 - $delta,
77 - $rate );
78 -
79 - wfWaitForSlaves( 10 );
 88+
 89+ $this->output( "Done!\n" );
8090 }
81 -} else {
82 - // Subselect should work on modern MySQLs etc
83 - echo "Using single-query mode...\n";
84 - $sql = "UPDATE $user SET user_editcount=(SELECT COUNT(*) FROM $revision WHERE rev_user=user_id)";
85 - $dbw->query( $sql );
8691 }
8792
88 -echo "Done!\n";
89 -
90 -
 93+$maintClass = "InitEditCount";
 94+require_once( DO_MAINTENANCE );
Index: branches/maintenance-work/maintenance/convertLinks.php
@@ -7,8 +7,223 @@
88 * @ingroup Maintenance
99 */
1010
11 -/** */
12 -require_once( "commandLine.inc" );
13 -require_once( "convertLinks.inc" );
 11+require_once( "Maintenance.php" );
1412
15 -convertLinks();
 13+class ConvertLinks extends Maintenance {
 14+
 15+ public function __construct() {
 16+ parent::__construct();
 17+ $this->mDescription = "Convert from the old links schema (string->ID) to the new schema (ID->ID)
 18+The wiki should be put into read-only mode while this script executes";
 19+ }
 20+
 21+ public function execute() {
 22+ global $wgDBtype;
 23+ if( $wgDBtype == 'postgres' ) {
 24+ $this->output( "Links table already ok on Postgres.\n" );
 25+ return;
 26+ }
 27+
 28+ $this->output( "Converting links table to ID-ID...\n" );
 29+
 30+ global $wgLang, $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
 31+ global $noKeys, $logPerformance, $fh;
 32+
 33+ $tuplesAdded = $numBadLinks = $curRowsRead = 0; #counters etc
 34+ $totalTuplesInserted = 0; # total tuples INSERTed into links_temp
 35+
 36+ $reportCurReadProgress = true; #whether or not to give progress reports while reading IDs from cur table
 37+ $curReadReportInterval = 1000; #number of rows between progress reports
 38+
 39+ $reportLinksConvProgress = true; #whether or not to give progress reports during conversion
 40+ $linksConvInsertInterval = 1000; #number of rows per INSERT
 41+
 42+ $initialRowOffset = 0;
 43+ #$finalRowOffset = 0; # not used yet; highest row number from links table to process
 44+
 45+ # Overwrite the old links table with the new one. If this is set to false,
 46+ # the new table will be left at links_temp.
 47+ $overwriteLinksTable = true;
 48+
 49+ # Don't create keys, and so allow duplicates in the new links table.
 50+ # This gives a huge speed improvement for very large links tables which are MyISAM. (What about InnoDB?)
 51+ $noKeys = false;
 52+
 53+
 54+ $logPerformance = false; # output performance data to a file
 55+ $perfLogFilename = "convLinksPerf.txt";
 56+ #--------------------------------------------------------------------
 57+
 58+ $dbw = wfGetDB( DB_MASTER );
 59+ list ($cur, $links, $links_temp, $links_backup) = $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' );
 60+
 61+ $res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
 62+ if ( $dbw->fieldType( $res, 0 ) == "int" ) {
 63+ $this->output( "Schema already converted\n" );
 64+ return;
 65+ }
 66+
 67+ $res = $dbw->query( "SELECT COUNT(*) AS count FROM $links" );
 68+ $row = $dbw->fetchObject($res);
 69+ $numRows = $row->count;
 70+ $dbw->freeResult( $res );
 71+
 72+ if ( $numRows == 0 ) {
 73+ $this->output( "Updating schema (no rows to convert)...\n" );
 74+ $this->createTempTable();
 75+ } else {
 76+ if ( $logPerformance ) { $fh = fopen ( $perfLogFilename, "w" ); }
 77+ $baseTime = $startTime = $this->getMicroTime();
 78+ # Create a title -> cur_id map
 79+ $this->output( "Loading IDs from $cur table...\n" );
 80+ $this->performanceLog ( "Reading $numRows rows from cur table...\n" );
 81+ $this->performanceLog ( "rows read vs seconds elapsed:\n" );
 82+
 83+ $dbw->bufferResults( false );
 84+ $res = $dbw->query( "SELECT cur_namespace,cur_title,cur_id FROM $cur" );
 85+ $ids = array();
 86+
 87+ while ( $row = $dbw->fetchObject( $res ) ) {
 88+ $title = $row->cur_title;
 89+ if ( $row->cur_namespace ) {
 90+ $title = $wgLang->getNsText( $row->cur_namespace ) . ":$title";
 91+ }
 92+ $ids[$title] = $row->cur_id;
 93+ $curRowsRead++;
 94+ if ($reportCurReadProgress) {
 95+ if (($curRowsRead % $curReadReportInterval) == 0) {
 96+ $this->performanceLog( $curRowsRead . " " . ($this->getMicroTime() - $baseTime) . "\n" );
 97+ $this->output( "\t$curRowsRead rows of $cur table read.\n" );
 98+ }
 99+ }
 100+ }
 101+ $dbw->freeResult( $res );
 102+ $dbw->bufferResults( true );
 103+ $this->output( "Finished loading IDs.\n\n" );
 104+ $this->performanceLog( "Took " . ($this->getMicroTime() - $baseTime) . " seconds to load IDs.\n\n" );
 105+ #--------------------------------------------------------------------
 106+
 107+ # Now, step through the links table (in chunks of $linksConvInsertInterval rows),
 108+ # convert, and write to the new table.
 109+ $this->createTempTable();
 110+ $this->performanceLog( "Resetting timer.\n\n" );
 111+ $baseTime = $this->getMicroTime();
 112+ $this->output( "Processing $numRows rows from $links table...\n" );
 113+ $this->performanceLog( "Processing $numRows rows from $links table...\n" );
 114+ $this->performanceLog( "rows inserted vs seconds elapsed:\n" );
 115+
 116+ for ($rowOffset = $initialRowOffset; $rowOffset < $numRows; $rowOffset += $linksConvInsertInterval) {
 117+ $sqlRead = "SELECT * FROM $links ";
 118+ $sqlRead = $dbw->limitResult($sqlRead, $linksConvInsertInterval,$rowOffset);
 119+ $res = $dbw->query($sqlRead);
 120+ if ( $noKeys ) {
 121+ $sqlWrite = array("INSERT INTO $links_temp (l_from,l_to) VALUES ");
 122+ } else {
 123+ $sqlWrite = array("INSERT IGNORE INTO $links_temp (l_from,l_to) VALUES ");
 124+ }
 125+
 126+ $tuplesAdded = 0; # no tuples added to INSERT yet
 127+ while ( $row = $dbw->fetchObject($res) ) {
 128+ $fromTitle = $row->l_from;
 129+ if ( array_key_exists( $fromTitle, $ids ) ) { # valid title
 130+ $from = $ids[$fromTitle];
 131+ $to = $row->l_to;
 132+ if ( $tuplesAdded != 0 ) {
 133+ $sqlWrite[] = ",";
 134+ }
 135+ $sqlWrite[] = "($from,$to)";
 136+ $tuplesAdded++;
 137+ } else { # invalid title
 138+ $numBadLinks++;
 139+ }
 140+ }
 141+ $dbw->freeResult($res);
 142+ #$this->output( "rowOffset: $rowOffset\ttuplesAdded: $tuplesAdded\tnumBadLinks: $numBadLinks\n" );
 143+ if ( $tuplesAdded != 0 ) {
 144+ if ($reportLinksConvProgress) {
 145+ $this->output( "Inserting $tuplesAdded tuples into $links_temp..." );
 146+ }
 147+ $dbw->query( implode("",$sqlWrite) );
 148+ $totalTuplesInserted += $tuplesAdded;
 149+ if ($reportLinksConvProgress)
 150+ $this->output( " done. Total $totalTuplesInserted tuples inserted.\n" );
 151+ $this->performanceLog( $totalTuplesInserted . " " . ($this->getMicroTime() - $baseTime) . "\n" );
 152+ }
 153+ }
 154+ $this->output( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n\n" );
 155+ $this->performanceLog( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n" );
 156+ $this->performanceLog( "Total execution time: " . ($this->getMicroTime() - $startTime) . " seconds.\n" );
 157+ if ( $logPerformance ) { fclose ( $fh ); }
 158+ }
 159+ #--------------------------------------------------------------------
 160+
 161+ if ( $overwriteLinksTable ) {
 162+ $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
 163+ if (!($dbConn->isOpen())) {
 164+ $this->output( "Opening connection to database failed.\n" );
 165+ return;
 166+ }
 167+ # Check for existing links_backup, and delete it if it exists.
 168+ $this->output( "Dropping backup links table if it exists..." );
 169+ $dbConn->query( "DROP TABLE IF EXISTS $links_backup", DB_MASTER);
 170+ $this->output( " done.\n" );
 171+
 172+ # Swap in the new table, and move old links table to links_backup
 173+ $this->output( "Swapping tables '$links' to '$links_backup'; '$links_temp' to '$links'..." );
 174+ $dbConn->query( "RENAME TABLE links TO $links_backup, $links_temp TO $links", DB_MASTER );
 175+ $this->output( " done.\n\n" );
 176+
 177+ $dbConn->close();
 178+ $this->output( "Conversion complete. The old table remains at $links_backup;\n" );
 179+ $this->output( "delete at your leisure.\n" );
 180+ } else {
 181+ $this->output( "Conversion complete. The converted table is at $links_temp;\n" );
 182+ $this->output( "the original links table is unchanged.\n" );
 183+ }
 184+ }
 185+
 186+ private function createTempTable() {
 187+ global $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
 188+ global $noKeys;
 189+ $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
 190+
 191+ if (!($dbConn->isOpen())) {
 192+ $this->output( "Opening connection to database failed.\n" );
 193+ return;
 194+ }
 195+ $links_temp = $dbConn->tableName( 'links_temp' );
 196+
 197+ $this->output( "Dropping temporary links table if it exists..." );
 198+ $dbConn->query( "DROP TABLE IF EXISTS $links_temp");
 199+ $this->output( " done.\n" );
 200+
 201+ $this->output( "Creating temporary links table..." );
 202+ if ( $noKeys ) {
 203+ $dbConn->query( "CREATE TABLE $links_temp ( " .
 204+ "l_from int(8) unsigned NOT NULL default '0', " .
 205+ "l_to int(8) unsigned NOT NULL default '0')");
 206+ } else {
 207+ $dbConn->query( "CREATE TABLE $links_temp ( " .
 208+ "l_from int(8) unsigned NOT NULL default '0', " .
 209+ "l_to int(8) unsigned NOT NULL default '0', " .
 210+ "UNIQUE KEY l_from(l_from,l_to), " .
 211+ "KEY (l_to))");
 212+ }
 213+ $this->output( " done.\n\n" );
 214+ }
 215+
 216+ private function performanceLog( $text ) {
 217+ global $logPerformance, $fh;
 218+ if ( $logPerformance ) {
 219+ fwrite( $fh, $text );
 220+ }
 221+ }
 222+
 223+ private function getMicroTime() { # return time in seconds, with microsecond accuracy
 224+ list($usec, $sec) = explode(" ", microtime());
 225+ return ((float)$usec + (float)$sec);
 226+ }
 227+}
 228+
 229+$maintClass = "ConvertLinks";
 230+require_once( DO_MAINTENANCE );

Status & tagging log