* Typo: $max was repeated in the prototype
[mediawiki.git] / maintenance / convertLinks.inc
blobfe523da9b39d5eb886fa4ff2fbffa4e5ee23fb3e
1 <?php
2 /**
3  * @todo document
4  * @package MediaWiki
5  * @subpackage Maintenance
6  */
8 /** */
9 function convertLinks() {
10         global $wgDBtype;
11         if( $wgDBtype == 'PostgreSQL' ) {
12                 print "Links table already ok on PostgreSQL.\n";
13                 return;
14         }
15         
16         print "Converting links table to ID-ID...\n";
17         
18         global $wgLang, $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
19         global $noKeys, $logPerformance, $fh;
20         
21         $numRows = $tuplesAdded = $numBadLinks = $curRowsRead = 0; #counters etc
22         $totalTuplesInserted = 0; # total tuples INSERTed into links_temp
24         $reportCurReadProgress = true; #whether or not to give progress reports while reading IDs from cur table
25         $curReadReportInterval = 1000; #number of rows between progress reports
27         $reportLinksConvProgress = true; #whether or not to give progress reports during conversion
28         $linksConvInsertInterval = 1000; #number of rows per INSERT
30         $initialRowOffset = 0;
31         #$finalRowOffset = 0; # not used yet; highest row number from links table to process
33         # Overwrite the old links table with the new one.  If this is set to false,
34         # the new table will be left at links_temp.
35         $overwriteLinksTable = true;
37         # Don't create keys, and so allow duplicates in the new links table.
38         # This gives a huge speed improvement for very large links tables which are MyISAM. (What about InnoDB?)
39         $noKeys = false;
42         $logPerformance = false; # output performance data to a file
43         $perfLogFilename = "convLinksPerf.txt";
44         #--------------------------------------------------------------------
45         
46         $dbw =& wfGetDB( DB_MASTER );
47         extract( $dbw->tableNames( 'cur', 'links', 'links_temp', 'links_backup' ) );
49         $res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
50         if ( $dbw->fieldType( $res, 0 ) == "int" ) {
51                 print "Schema already converted\n";
52                 return;
53         }
54         
55         $res = $dbw->query( "SELECT COUNT(*) AS count FROM $links" );
56         $row = $dbw->fetchObject($res);
57         $numRows = $row->count;
58         $dbw->freeResult( $res );
60         if ( $numRows == 0 ) {
61                 print "Updating schema (no rows to convert)...\n";
62                 createTempTable();
63         } else {
64                 if ( $logPerformance ) { $fh = fopen ( $perfLogFilename, "w" ); }
65                 $baseTime = $startTime = getMicroTime();
66                 # Create a title -> cur_id map
67                 print "Loading IDs from $cur table...\n";
68                 performanceLog ( "Reading $numRows rows from cur table...\n" );
69                 performanceLog ( "rows read vs seconds elapsed:\n" );
70                 
71                 $dbw->bufferResults( false );
72                 $res = $dbw->query( "SELECT cur_namespace,cur_title,cur_id FROM $cur" );
73                 $ids = array();
75                 while ( $row = $dbw->fetchObject( $res ) ) {
76                         $title = $row->cur_title;
77                         if ( $row->cur_namespace ) {
78                                 $title = $wgLang->getNsText( $row->cur_namespace ) . ":$title";
79                         }
80                         $ids[$title] = $row->cur_id;
81                         $curRowsRead++;
82                         if ($reportCurReadProgress) {
83                                 if (($curRowsRead % $curReadReportInterval) == 0) {
84                                         performanceLog( $curRowsRead . " " . (getMicroTime() - $baseTime) . "\n" );
85                                         print "\t$curRowsRead rows of $cur table read.\n";      
86                                 }
87                         }
88                 }
89                 $dbw->freeResult( $res );
90                 $dbw->bufferResults( true );
91                 print "Finished loading IDs.\n\n";
92                 performanceLog( "Took " . (getMicroTime() - $baseTime) . " seconds to load IDs.\n\n" );
93         #--------------------------------------------------------------------
95                 # Now, step through the links table (in chunks of $linksConvInsertInterval rows),
96                 # convert, and write to the new table.
97                 createTempTable();
98                 performanceLog( "Resetting timer.\n\n" );
99                 $baseTime = getMicroTime();
100                 print "Processing $numRows rows from $links table...\n";
101                 performanceLog( "Processing $numRows rows from $links table...\n" );
102                 performanceLog( "rows inserted vs seconds elapsed:\n" );
103                 
104                 for ($rowOffset = $initialRowOffset; $rowOffset < $numRows; $rowOffset += $linksConvInsertInterval) {
105                         $sqlRead = "SELECT * FROM $links ".$dbw->limitResult($linksConvInsertInterval,$rowOffset);
106                         $res = $dbw->query($sqlRead);
107                         if ( $noKeys ) {
108                                 $sqlWrite = array("INSERT INTO $links_temp (l_from,l_to) VALUES ");
109                         } else {
110                                 $sqlWrite = array("INSERT IGNORE INTO $links_temp (l_from,l_to) VALUES ");
111                         }
112                         
113                         $tuplesAdded = 0; # no tuples added to INSERT yet
114                         while ( $row = $dbw->fetchObject($res) ) {
115                                 $fromTitle = $row->l_from; 
116                                 if ( array_key_exists( $fromTitle, $ids ) ) { # valid title
117                                         $from = $ids[$fromTitle];
118                                         $to = $row->l_to;
119                                         if ( $tuplesAdded != 0 ) {
120                                                 $sqlWrite[] = ",";
121                                         }
122                                         $sqlWrite[] = "($from,$to)";
123                                         $tuplesAdded++;                         
124                                 } else { # invalid title
125                                         $numBadLinks++;
126                                 }
127                         }
128                         $dbw->freeResult($res);
129                         #print "rowOffset: $rowOffset\ttuplesAdded: $tuplesAdded\tnumBadLinks: $numBadLinks\n";
130                         if ( $tuplesAdded != 0  ) {
131                                 if ($reportLinksConvProgress) {
132                                         print "Inserting $tuplesAdded tuples into $links_temp...";
133                                 }
134                                 $dbw->query( implode("",$sqlWrite) );
135                                 $totalTuplesInserted += $tuplesAdded;
136                                 if ($reportLinksConvProgress)
137                                         print " done. Total $totalTuplesInserted tuples inserted.\n";
138                                         performanceLog( $totalTuplesInserted . " " . (getMicroTime() - $baseTime) . "\n"  );
139                         }
140                 }
141                 print "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n\n";
142                 performanceLog( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n" );
143                 performanceLog( "Total execution time: " . (getMicroTime() - $startTime) . " seconds.\n" );
144                 if ( $logPerformance ) { fclose ( $fh ); }
145         }
146         #--------------------------------------------------------------------
148         if ( $overwriteLinksTable ) {
149                 $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
150                 if (!($dbConn->isOpen())) {
151                         print "Opening connection to database failed.\n";
152                         return;
153                 }
154                 # Check for existing links_backup, and delete it if it exists.
155                 print "Dropping backup links table if it exists...";
156                 $dbConn->query( "DROP TABLE IF EXISTS $links_backup", DB_MASTER);
157                 print " done.\n";
158                 
159                 # Swap in the new table, and move old links table to links_backup
160                 print "Swapping tables '$links' to '$links_backup'; '$links_temp' to '$links'...";
161                 $dbConn->query( "RENAME TABLE links TO $links_backup, $links_temp TO $links", DB_MASTER );
162                 print " done.\n\n";
163                 
164                 $dbConn->close();
165                 print "Conversion complete. The old table remains at $links_backup;\n";
166                 print "delete at your leisure.\n";
167         } else {
168                 print "Conversion complete.  The converted table is at $links_temp;\n";
169                 print "the original links table is unchanged.\n";
170         }
173 #--------------------------------------------------------------------
175 function createTempTable() {
176         global $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname;
177         global $noKeys;
178         $dbConn = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
179         
180         if (!($dbConn->isOpen())) {
181                 print "Opening connection to database failed.\n";
182                 return;
183         }
184         $links_temp = $dbConn->tableName( 'links_temp' );
185         
186         print "Dropping temporary links table if it exists...";
187         $dbConn->query( "DROP TABLE IF EXISTS $links_temp");
188         print " done.\n";
189         
190         print "Creating temporary links table...";
191         if ( $noKeys ) {
192                 $dbConn->query( "CREATE TABLE $links_temp ( " .
193                 "l_from int(8) unsigned NOT NULL default '0', " .
194                 "l_to int(8) unsigned NOT NULL default '0')");
195         } else {
196                 $dbConn->query( "CREATE TABLE $links_temp ( " .
197                 "l_from int(8) unsigned NOT NULL default '0', " .
198                 "l_to int(8) unsigned NOT NULL default '0', " .
199                 "UNIQUE KEY l_from(l_from,l_to), " .
200                 "KEY (l_to))");
201         }
202         print " done.\n\n";
205 function performanceLog( $text ) {
206         global $logPerformance, $fh;
207         if ( $logPerformance ) {
208                 fwrite( $fh, $text );
209         }
212 function getMicroTime() { # return time in seconds, with microsecond accuracy
213         list($usec, $sec) = explode(" ", microtime());
214         return ((float)$usec + (float)$sec);