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