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