MediaWiki  REL1_22
upgradeLogging.php
Go to the documentation of this file.
00001 <?php
00024 require __DIR__ . '/../commandLine.inc';
00025 
00032 class UpdateLogging {
00033 
00037     public $dbw;
00038     public $batchSize = 1000;
00039     public $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();