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