MediaWiki  REL1_20
upgradeLogging.php
Go to the documentation of this file.
00001 <?php
00024 require( __DIR__ . '/../commandLine.inc' );
00025 
00032 class UpdateLogging {
00033 
00037         var $dbw;
00038         var $batchSize = 1000;
00039         var $minTs = false;
00040 
00041         function execute() {
00042                 $this->dbw = wfGetDB( DB_MASTER );
00043                 $logging = $this->dbw->tableName( 'logging' );
00044                 $logging_1_10 = $this->dbw->tableName( 'logging_1_10' );
00045                 $logging_pre_1_10 = $this->dbw->tableName( 'logging_pre_1_10' );
00046 
00047                 if ( $this->dbw->tableExists( 'logging_pre_1_10' ) && !$this->dbw->tableExists( 'logging' ) ) {
00048                         # Fix previous aborted run
00049                         echo "Cleaning up from previous aborted run\n";
00050                         $this->dbw->query( "RENAME TABLE $logging_pre_1_10 TO $logging", __METHOD__ );
00051                 }
00052 
00053                 if ( $this->dbw->tableExists( 'logging_pre_1_10' ) ) {
00054                         echo "This script has already been run to completion\n";
00055                         return;
00056                 }
00057 
00058                 # Create the target table
00059                 if ( !$this->dbw->tableExists( 'logging_1_10' ) ) {
00060                         global $wgDBTableOptions;
00061 
00062                         $sql = <<<EOT
00063 CREATE TABLE $logging_1_10 (
00064   -- Log ID, for referring to this specific log entry, probably for deletion and such.
00065   log_id int unsigned NOT NULL auto_increment,
00066 
00067   -- Symbolic keys for the general log type and the action type
00068   -- within the log. The output format will be controlled by the
00069   -- action field, but only the type controls categorization.
00070   log_type varbinary(10) NOT NULL default '',
00071   log_action varbinary(10) NOT NULL default '',
00072 
00073   -- Timestamp. Duh.
00074   log_timestamp binary(14) NOT NULL default '19700101000000',
00075 
00076   -- The user who performed this action; key to user_id
00077   log_user int unsigned NOT NULL default 0,
00078 
00079   -- Key to the page affected. Where a user is the target,
00080   -- this will point to the user page.
00081   log_namespace int NOT NULL default 0,
00082   log_title varchar(255) binary NOT NULL default '',
00083 
00084   -- Freeform text. Interpreted as edit history comments.
00085   log_comment varchar(255) NOT NULL default '',
00086 
00087   -- LF separated list of miscellaneous parameters
00088   log_params blob NOT NULL,
00089 
00090   -- rev_deleted for logs
00091   log_deleted tinyint unsigned NOT NULL default '0',
00092 
00093   PRIMARY KEY log_id (log_id),
00094   KEY type_time (log_type, log_timestamp),
00095   KEY user_time (log_user, log_timestamp),
00096   KEY page_time (log_namespace, log_title, log_timestamp),
00097   KEY times (log_timestamp)
00098 
00099 ) $wgDBTableOptions
00100 EOT;
00101                         echo "Creating table logging_1_10\n";
00102                         $this->dbw->query( $sql, __METHOD__ );
00103                 }
00104 
00105                 # Synchronise the tables
00106                 echo "Doing initial sync...\n";
00107                 $this->sync( 'logging', 'logging_1_10' );
00108                 echo "Sync done\n\n";
00109 
00110                 # Rename the old table away
00111                 echo "Renaming the old table to $logging_pre_1_10\n";
00112                 $this->dbw->query( "RENAME TABLE $logging TO $logging_pre_1_10", __METHOD__ );
00113 
00114                 # Copy remaining old rows
00115                 # Done before the new table is active so that $copyPos is accurate
00116                 echo "Doing final sync...\n";
00117                 $this->sync( 'logging_pre_1_10', 'logging_1_10' );
00118 
00119                 # Move the new table in
00120                 echo "Moving the new table in...\n";
00121                 $this->dbw->query( "RENAME TABLE $logging_1_10 TO $logging", __METHOD__ );
00122                 echo "Finished.\n";
00123         }
00124 
00128         function sync( $srcTable, $dstTable ) {
00129                 $batchSize = 1000;
00130                 $minTs = $this->dbw->selectField( $srcTable, 'MIN(log_timestamp)', false, __METHOD__ );
00131                 $minTsUnix = wfTimestamp( TS_UNIX, $minTs );
00132                 $numRowsCopied = 0;
00133 
00134                 while ( true ) {
00135                         $maxTs = $this->dbw->selectField( $srcTable, 'MAX(log_timestamp)', false, __METHOD__ );
00136                         $copyPos = $this->dbw->selectField( $dstTable, 'MAX(log_timestamp)', false, __METHOD__ );
00137                         $maxTsUnix = wfTimestamp( TS_UNIX, $maxTs );
00138                         $copyPosUnix = wfTimestamp( TS_UNIX, $copyPos );
00139 
00140                         if ( $copyPos === null ) {
00141                                 $percent = 0;
00142                         } else {
00143                                 $percent = ( $copyPosUnix - $minTsUnix ) / ( $maxTsUnix - $minTsUnix ) * 100;
00144                         }
00145                         printf( "%s  %.2f%%\n", $copyPos, $percent );
00146 
00147                         # Handle all entries with timestamp equal to $copyPos
00148                         if ( $copyPos !== null ) {
00149                                 $numRowsCopied += $this->copyExactMatch( $srcTable, $dstTable, $copyPos );
00150                         }
00151 
00152                         # Now copy a batch of rows
00153                         if ( $copyPos === null ) {
00154                                 $conds = false;
00155                         } else {
00156                                 $conds = array( 'log_timestamp > ' . $this->dbw->addQuotes( $copyPos ) );
00157                         }
00158                         $srcRes = $this->dbw->select( $srcTable, '*', $conds, __METHOD__,
00159                                 array( 'LIMIT' => $batchSize, 'ORDER BY' => 'log_timestamp' ) );
00160 
00161                         if ( ! $srcRes->numRows() ) {
00162                                 # All done
00163                                 break;
00164                         }
00165 
00166                         $batch = array();
00167                         foreach ( $srcRes as $srcRow ) {
00168                                 $batch[] = (array)$srcRow;
00169                         }
00170                         $this->dbw->insert( $dstTable, $batch, __METHOD__ );
00171                         $numRowsCopied += count( $batch );
00172 
00173                         wfWaitForSlaves();
00174                 }
00175                 echo "Copied $numRowsCopied rows\n";
00176         }
00177 
00178         function copyExactMatch( $srcTable, $dstTable, $copyPos ) {
00179                 $numRowsCopied = 0;
00180                 $srcRes = $this->dbw->select( $srcTable, '*', array( 'log_timestamp' => $copyPos ), __METHOD__ );
00181                 $dstRes = $this->dbw->select( $dstTable, '*', array( 'log_timestamp' => $copyPos ), __METHOD__ );
00182 
00183                 if ( $srcRes->numRows() ) {
00184                         $srcRow = $srcRes->fetchObject();
00185                         $srcFields = array_keys( (array)$srcRow );
00186                         $srcRes->seek( 0 );
00187                         $dstRowsSeen = array();
00188 
00189                         # Make a hashtable of rows that already exist in the destination
00190                         foreach ( $dstRes as $dstRow ) {
00191                                 $reducedDstRow = array();
00192                                 foreach ( $srcFields as $field ) {
00193                                         $reducedDstRow[$field] = $dstRow->$field;
00194                                 }
00195                                 $hash = md5( serialize( $reducedDstRow ) );
00196                                 $dstRowsSeen[$hash] = true;
00197                         }
00198 
00199                         # Copy all the source rows that aren't already in the destination
00200                         foreach ( $srcRes as $srcRow ) {
00201                                 $hash = md5( serialize( (array)$srcRow ) );
00202                                 if ( !isset( $dstRowsSeen[$hash] ) ) {
00203                                         $this->dbw->insert( $dstTable, (array)$srcRow, __METHOD__ );
00204                                         $numRowsCopied++;
00205                                 }
00206                         }
00207                 }
00208                 return $numRowsCopied;
00209         }
00210 }
00211 
00212 $ul = new UpdateLogging;
00213 $ul->execute();
00214