MediaWiki REL1_35
rebuildLocalisationCache.php
Go to the documentation of this file.
1<?php
2
35
36require_once __DIR__ . '/Maintenance.php';
37
44 public function __construct() {
45 parent::__construct();
46 $this->addDescription( 'Rebuild the localisation cache' );
47 $this->addOption( 'force', 'Rebuild all files, even ones not out of date' );
48 $this->addOption( 'threads', 'Fork more than one thread', false, true );
49 $this->addOption( 'outdir', 'Override the output directory (normally $wgCacheDirectory)',
50 false, true );
51 $this->addOption( 'lang', 'Only rebuild these languages, comma separated.',
52 false, true );
53 $this->addOption(
54 'store-class',
55 'Override the LC store class (normally $wgLocalisationCacheConf[\'storeClass\'])',
56 false,
57 true
58 );
59 }
60
61 public function finalSetup() {
62 # This script needs to be run to build the inital l10n cache. But if
63 # $wgLanguageCode is not 'en', it won't be able to run because there is
64 # no l10n cache. Break the cycle by forcing $wgLanguageCode = 'en'.
65 global $wgLanguageCode;
66 $wgLanguageCode = 'en';
67 parent::finalSetup();
68 }
69
70 public function execute() {
72
73 $force = $this->hasOption( 'force' );
74 $threads = $this->getOption( 'threads', 1 );
75 if ( $threads < 1 || $threads != intval( $threads ) ) {
76 $this->output( "Invalid thread count specified; running single-threaded.\n" );
77 $threads = 1;
78 }
79 if ( $threads > 1 && wfIsWindows() ) {
80 $this->output( "Threaded rebuild is not supported on Windows; running single-threaded.\n" );
81 $threads = 1;
82 }
83 if ( $threads > 1 && !function_exists( 'pcntl_fork' ) ) {
84 $this->output( "PHP pcntl extension is not present; running single-threaded.\n" );
85 $threads = 1;
86 }
87
89 // Allow fallbacks to create CDB files
90 $conf['manualRecache'] = false;
91 $conf['forceRecache'] = $force || !empty( $conf['forceRecache'] );
92 if ( $this->hasOption( 'outdir' ) ) {
93 $conf['storeDirectory'] = $this->getOption( 'outdir' );
94 }
95
96 if ( $this->hasOption( 'store-class' ) ) {
97 $conf['storeClass'] = $this->getOption( 'store-class' );
98 }
99 // XXX Copy-pasted from ServiceWiring.php. Do we need a factory for this one caller?
100 $services = MediaWikiServices::getInstance();
102 new ServiceOptions(
103 LocalisationCache::CONSTRUCTOR_OPTIONS,
104 $conf,
105 $services->getMainConfig()
106 ),
107 LocalisationCache::getStoreFromConf( $conf, $wgCacheDirectory ),
108 LoggerFactory::getInstance( 'localisation' ),
109 [ function () use ( $services ) {
110 MessageBlobStore::clearGlobalCacheEntry( $services->getMainWANObjectCache() );
111 } ],
112 $services->getLanguageNameUtils(),
113 $services->getHookContainer()
114 );
115
116 $allCodes = array_keys( $services
117 ->getLanguageNameUtils()
118 ->getLanguageNames( null, 'mwfile' ) );
119 if ( $this->hasOption( 'lang' ) ) {
120 # Validate requested languages
121 $codes = array_intersect( $allCodes,
122 explode( ',', $this->getOption( 'lang' ) ) );
123 # Bailed out if nothing is left
124 if ( count( $codes ) == 0 ) {
125 $this->fatalError( 'None of the languages specified exists.' );
126 }
127 } else {
128 # By default get all languages
129 $codes = $allCodes;
130 }
131 sort( $codes );
132
133 // Initialise and split into chunks
134 $numRebuilt = 0;
135 $total = count( $codes );
136 $chunks = array_chunk( $codes, ceil( count( $codes ) / $threads ) );
137 $pids = [];
138 $parentStatus = 0;
139 foreach ( $chunks as $codes ) {
140 // Do not fork for only one thread
141 $pid = ( $threads > 1 ) ? pcntl_fork() : -1;
142
143 if ( $pid === 0 ) {
144 // Child, reseed because there is no bug in PHP:
145 // https://bugs.php.net/bug.php?id=42465
146 mt_srand( getmypid() );
147
148 $this->doRebuild( $codes, $lc, $force );
149 exit( 0 );
150 } elseif ( $pid === -1 ) {
151 // Fork failed or one thread, do it serialized
152 $numRebuilt += $this->doRebuild( $codes, $lc, $force );
153 } else {
154 // Main thread
155 $pids[] = $pid;
156 }
157 }
158 // Wait for all children
159 foreach ( $pids as $pid ) {
160 $status = 0;
161 pcntl_waitpid( $pid, $status );
162 if ( pcntl_wexitstatus( $status ) ) {
163 // Pass a fatal error code through to the caller
164 $parentStatus = pcntl_wexitstatus( $status );
165 }
166 }
167
168 if ( !$pids ) {
169 $this->output( "$numRebuilt languages rebuilt out of $total\n" );
170 if ( $numRebuilt === 0 ) {
171 $this->output( "Use --force to rebuild the caches which are still fresh.\n" );
172 }
173 }
174 if ( $parentStatus ) {
175 exit( $parentStatus );
176 }
177 }
178
187 private function doRebuild( $codes, $lc, $force ) {
188 $numRebuilt = 0;
189 foreach ( $codes as $code ) {
190 if ( $force || $lc->isExpired( $code ) ) {
191 $this->output( "Rebuilding $code...\n" );
192 $lc->recache( $code );
193 $numRebuilt++;
194 }
195 }
196
197 return $numRebuilt;
198 }
199
205 public function setForce( $forced = true ) {
206 $this->mOptions['force'] = $forced;
207 }
208}
209
210$maintClass = RebuildLocalisationCache::class;
211require_once RUN_MAINTENANCE_IF_MAIN;
$wgLanguageCode
Site language code.
$wgCacheDirectory
Directory for caching data in the local filesystem.
$wgLocalisationCacheConf
Localisation cache configuration.
wfIsWindows()
Check if the operating system is Windows.
const RUN_MAINTENANCE_IF_MAIN
A localisation cache optimised for loading large amounts of data for many languages.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
output( $out, $channel=null)
Throw some output to the user.
hasOption( $name)
Checks to see if a particular option was set.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
A class for passing options to services.
PSR-3 logger instance factory.
MediaWikiServices is the service locator for the application scope of MediaWiki.
static clearGlobalCacheEntry(WANObjectCache $cache)
Invalidate cache keys for all known modules.
Maintenance script to rebuild the localisation cache.
finalSetup()
Handle some last-minute setup here.
setForce( $forced=true)
Sets whether a run of this maintenance script has the force parameter set.
doRebuild( $codes, $lc, $force)
Helper function to rebuild list of languages codes.