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