MediaWiki  REL1_22
rebuildLocalisationCache.php
Go to the documentation of this file.
00001 <?php
00002 
00032 require_once __DIR__ . '/Maintenance.php';
00033 
00039 class RebuildLocalisationCache extends Maintenance {
00040     public function __construct() {
00041         parent::__construct();
00042         $this->mDescription = "Rebuild the localisation cache";
00043         $this->addOption( 'force', 'Rebuild all files, even ones not out of date' );
00044         $this->addOption( 'threads', 'Fork more than one thread', false, true );
00045         $this->addOption( 'outdir', 'Override the output directory (normally $wgCacheDirectory)',
00046             false, true );
00047         $this->addOption( 'lang', 'Only rebuild these languages, comma separated.',
00048             false, true );
00049     }
00050 
00051     public function memoryLimit() {
00052         if ( $this->hasOption( 'memory-limit' ) ) {
00053             return parent::memoryLimit();
00054         }
00055         return '1000M';
00056     }
00057 
00058     public function finalSetup() {
00059         # This script needs to be run to build the inital l10n cache. But if
00060         # $wgLanguageCode is not 'en', it won't be able to run because there is
00061         # no l10n cache. Break the cycle by forcing $wgLanguageCode = 'en'.
00062         global $wgLanguageCode;
00063         $wgLanguageCode = 'en';
00064         parent::finalSetup();
00065     }
00066 
00067     public function execute() {
00068         global $wgLocalisationCacheConf;
00069 
00070         $force = $this->hasOption( 'force' );
00071         $threads = $this->getOption( 'threads', 1 );
00072         if ( $threads < 1 || $threads != intval( $threads ) ) {
00073             $this->output( "Invalid thread count specified; running single-threaded.\n" );
00074             $threads = 1;
00075         }
00076         if ( $threads > 1 && wfIsWindows() ) {
00077             $this->output( "Threaded rebuild is not supported on Windows; running single-threaded.\n" );
00078             $threads = 1;
00079         }
00080         if ( $threads > 1 && !function_exists( 'pcntl_fork' ) ) {
00081             $this->output( "PHP pcntl extension is not present; running single-threaded.\n" );
00082             $threads = 1;
00083         }
00084 
00085         $conf = $wgLocalisationCacheConf;
00086         $conf['manualRecache'] = false; // Allow fallbacks to create CDB files
00087         if ( $force ) {
00088             $conf['forceRecache'] = true;
00089         }
00090         if ( $this->hasOption( 'outdir' ) ) {
00091             $conf['storeDirectory'] = $this->getOption( 'outdir' );
00092         }
00093         $lc = new LocalisationCache_BulkLoad( $conf );
00094 
00095         $allCodes = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
00096         if ( $this->hasOption( 'lang' ) ) {
00097             # Validate requested languages
00098             $codes = array_intersect( $allCodes,
00099                 explode( ',', $this->getOption( 'lang' ) ) );
00100             # Bailed out if nothing is left
00101             if ( count( $codes ) == 0 ) {
00102                 $this->error( 'None of the languages specified exists.', 1 );
00103             }
00104         } else {
00105             # By default get all languages
00106             $codes = $allCodes;
00107         }
00108         sort( $codes );
00109 
00110         // Initialise and split into chunks
00111         $numRebuilt = 0;
00112         $total = count( $codes );
00113         $chunks = array_chunk( $codes, ceil( count( $codes ) / $threads ) );
00114         $pids = array();
00115         foreach ( $chunks as $codes ) {
00116             // Do not fork for only one thread
00117             $pid = ( $threads > 1 ) ? pcntl_fork() : -1;
00118 
00119             if ( $pid === 0 ) {
00120                 // Child, reseed because there is no bug in PHP:
00121                 // http://bugs.php.net/bug.php?id=42465
00122                 mt_srand( getmypid() );
00123                 $numRebuilt = $this->doRebuild( $codes, $lc, $force );
00124                 // Abuse the exit value for the count of rebuild languages
00125                 exit( $numRebuilt );
00126             } elseif ( $pid === -1 ) {
00127                 // Fork failed or one thread, do it serialized
00128                 $numRebuilt += $this->doRebuild( $codes, $lc, $force );
00129             } else {
00130                 // Main thread
00131                 $pids[] = $pid;
00132             }
00133         }
00134         // Wait for all children
00135         foreach ( $pids as $pid ) {
00136             $status = 0;
00137             pcntl_waitpid( $pid, $status );
00138             // Fetch the count from the return value
00139             $numRebuilt += pcntl_wexitstatus( $status );
00140         }
00141 
00142         $this->output( "$numRebuilt languages rebuilt out of $total\n" );
00143         if ( $numRebuilt === 0 ) {
00144             $this->output( "Use --force to rebuild the caches which are still fresh.\n" );
00145         }
00146     }
00147 
00156     private function doRebuild( $codes, $lc, $force ) {
00157         $numRebuilt = 0;
00158         foreach ( $codes as $code ) {
00159             if ( $force || $lc->isExpired( $code ) ) {
00160                 $this->output( "Rebuilding $code...\n" );
00161                 $lc->recache( $code );
00162                 $numRebuilt++;
00163             }
00164         }
00165         return $numRebuilt;
00166     }
00167 
00173     public function setForce( $forced = true ) {
00174         $this->mOptions['force'] = $forced;
00175     }
00176 }
00177 
00178 $maintClass = "RebuildLocalisationCache";
00179 require_once RUN_MAINTENANCE_IF_MAIN;