MediaWiki  REL1_21
populateImageSha1.php
Go to the documentation of this file.
00001 <?php
00024 require_once( __DIR__ . '/Maintenance.php' );
00025 
00031 class PopulateImageSha1 extends LoggedUpdateMaintenance {
00032         public function __construct() {
00033                 parent::__construct();
00034                 $this->mDescription = "Populate the img_sha1 field";
00035                 $this->addOption( 'force', "Recalculate sha1 for rows that already have a value" );
00036                 $this->addOption( 'method', "Use 'pipe' to pipe to mysql command line,\n" .
00037                         "\t\tdefault uses Database class", false, true );
00038                 $this->addOption( 'file', 'Fix for a specific file, without File: namespace prefixed', false, true );
00039         }
00040 
00041         protected function getUpdateKey() {
00042                 return 'populate img_sha1';
00043         }
00044 
00045         protected function updateSkippedMessage() {
00046                 return 'img_sha1 column of image table already populated.';
00047         }
00048 
00049         public function execute() {
00050                 if ( $this->getOption( 'file' ) ) {
00051                         $this->doDBUpdates(); // skip update log checks/saves
00052                 } else {
00053                         parent::execute();
00054                 }
00055         }
00056 
00057         public function doDBUpdates() {
00058                 $method = $this->getOption( 'method', 'normal' );
00059                 $file = $this->getOption( 'file', '' );
00060                 $force = $this->getOption( 'force' );
00061                 $isRegen = ( $force || $file != '' ); // forced recalculation?
00062 
00063                 $t = -microtime( true );
00064                 $dbw = wfGetDB( DB_MASTER );
00065                 if ( $file != '' ) {
00066                         $res = $dbw->select(
00067                                 'image',
00068                                 array( 'img_name' ),
00069                                 array( 'img_name' => $file ),
00070                                 __METHOD__
00071                         );
00072                         if ( !$res ) {
00073                                 $this->error( "No such file: $file", true );
00074                                 return false;
00075                         }
00076                         $this->output( "Populating img_sha1 field for specified files\n" );
00077                 } else {
00078                         if ( $force ) {
00079                                 $conds = array();
00080                                 $this->output( "Populating and recalculating img_sha1 field\n" );
00081                         } else {
00082                                 $conds = array( 'img_sha1' => '' );
00083                                 $this->output( "Populating img_sha1 field\n" );
00084                         }
00085                         $res = $dbw->select( 'image', array( 'img_name' ), $conds, __METHOD__ );
00086                 }
00087 
00088                 $imageTable = $dbw->tableName( 'image' );
00089                 $oldImageTable = $dbw->tableName( 'oldimage' );
00090 
00091                 if ( $method == 'pipe' ) {
00092                         // Opening a pipe allows the SHA-1 operation to be done in parallel
00093                         // with the database write operation, because the writes are queued
00094                         // in the pipe buffer. This can improve performance by up to a
00095                         // factor of 2.
00096                         global $wgDBuser, $wgDBserver, $wgDBpassword, $wgDBname;
00097                         $cmd = 'mysql -u' . wfEscapeShellArg( $wgDBuser ) .
00098                                 ' -h' . wfEscapeShellArg( $wgDBserver ) .
00099                                 ' -p' . wfEscapeShellArg( $wgDBpassword, $wgDBname );
00100                         $this->output( "Using pipe method\n" );
00101                         $pipe = popen( $cmd, 'w' );
00102                 }
00103 
00104                 $numRows = $res->numRows();
00105                 $i = 0;
00106                 foreach ( $res as $row ) {
00107                         if ( $i % $this->mBatchSize == 0 ) {
00108                                 $this->output( sprintf(
00109                                         "Done %d of %d, %5.3f%%  \r", $i, $numRows, $i / $numRows * 100 ) );
00110                                 wfWaitForSlaves();
00111                         }
00112                         $file = wfLocalFile( $row->img_name );
00113                         if ( !$file ) {
00114                                 continue;
00115                         }
00116                         // Upgrade the current file version...
00117                         $sha1 = $file->getRepo()->getFileSha1( $file->getPath() );
00118                         if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly
00119                                 if ( $isRegen && $file->getSha1() !== $sha1 ) {
00120                                         // The population was probably done already. If the old SHA1
00121                                         // does not match, then both fix the SHA1 and the metadata.
00122                                         $file->upgradeRow();
00123                                 } else {
00124                                         $sql = "UPDATE $imageTable SET img_sha1=" . $dbw->addQuotes( $sha1 ) .
00125                                                 " WHERE img_name=" . $dbw->addQuotes( $file->getName() );
00126                                         if ( $method == 'pipe' ) {
00127                                                 fwrite( $pipe, "$sql;\n" );
00128                                         } else {
00129                                                 $dbw->query( $sql, __METHOD__ );
00130                                         }
00131                                 }
00132                         }
00133                         // Upgrade the old file versions...
00134                         foreach ( $file->getHistory() as $oldFile ) {
00135                                 $sha1 = $oldFile->getRepo()->getFileSha1( $oldFile->getPath() );
00136                                 if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly
00137                                         if ( $isRegen && $oldFile->getSha1() !== $sha1 ) {
00138                                                 // The population was probably done already. If the old SHA1
00139                                                 // does not match, then both fix the SHA1 and the metadata.
00140                                                 $oldFile->upgradeRow();
00141                                         } else {
00142                                                 $sql = "UPDATE $oldImageTable SET oi_sha1=" . $dbw->addQuotes( $sha1 ) .
00143                                                         " WHERE (oi_name=" . $dbw->addQuotes( $oldFile->getName() ) . " AND" .
00144                                                         " oi_archive_name=" . $dbw->addQuotes( $oldFile->getArchiveName() ) . ")";
00145                                                 if ( $method == 'pipe' ) {
00146                                                         fwrite( $pipe, "$sql;\n" );
00147                                                 } else {
00148                                                         $dbw->query( $sql, __METHOD__ );
00149                                                 }
00150                                         }
00151                                 }
00152                         }
00153                         $i++;
00154                 }
00155                 if ( $method == 'pipe' ) {
00156                         fflush( $pipe );
00157                         pclose( $pipe );
00158                 }
00159                 $t += microtime( true );
00160                 $this->output( sprintf( "\nDone %d files in %.1f seconds\n", $numRows, $t ) );
00161 
00162                 return !$file; // we only updated *some* files, don't log
00163         }
00164 }
00165 
00166 $maintClass = "PopulateImageSha1";
00167 require_once( RUN_MAINTENANCE_IF_MAIN );