MediaWiki REL1_39
rebuildFileCache.php
Go to the documentation of this file.
1<?php
27use Wikimedia\AtEase\AtEase;
28
29require_once __DIR__ . '/Maintenance.php';
30
37 private $enabled = true;
38
39 public function __construct() {
40 parent::__construct();
41 $this->addDescription( 'Build the file cache' );
42 $this->addOption( 'start', 'Page_id to start from', false, true );
43 $this->addOption( 'end', 'Page_id to end on', false, true );
44 $this->addOption( 'overwrite', 'Refresh page cache' );
45 $this->addOption( 'all', 'Build the file cache for pages in all namespaces, not just content pages' );
46 $this->setBatchSize( 100 );
47 }
48
49 public function finalSetup( SettingsBuilder $settingsBuilder = null ) {
50 $this->enabled = $settingsBuilder->getConfig()->get( MainConfigNames::UseFileCache );
51 // Script will handle capturing output and saving it itself
52 $settingsBuilder->putConfigValue( MainConfigNames::UseFileCache, false );
53
54 // Avoid DB writes (like enotif/counters)
55 MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()
56 ->setReason( 'Building cache' );
57
58 // Ensure no debug-specific logic ends up in the cache (must be after Setup.php)
59 MWDebug::deinit();
60
61 parent::finalSetup( $settingsBuilder );
62 }
63
64 public function execute() {
65 if ( !$this->enabled ) {
66 $this->fatalError( "Nothing to do -- \$wgUseFileCache is disabled." );
67 }
68
69 $start = $this->getOption( 'start', "0" );
70 if ( !ctype_digit( $start ) ) {
71 $this->fatalError( "Invalid value for start parameter." );
72 }
73 $start = intval( $start );
74
75 $end = $this->getOption( 'end', "0" );
76 if ( !ctype_digit( $end ) ) {
77 $this->fatalError( "Invalid value for end parameter." );
78 }
79 $end = intval( $end );
80
81 $this->output( "Building page file cache from page_id {$start}!\n" );
82
83 $dbr = $this->getDB( DB_REPLICA );
84 $batchSize = $this->getBatchSize();
85 $overwrite = $this->hasOption( 'overwrite' );
86 $start = ( $start > 0 )
87 ? $start
88 : $dbr->selectField( 'page', 'MIN(page_id)', '', __METHOD__ );
89 $end = ( $end > 0 )
90 ? $end
91 : $dbr->selectField( 'page', 'MAX(page_id)', '', __METHOD__ );
92 if ( !$start ) {
93 $this->fatalError( "Nothing to do." );
94 }
95
96 $where = [];
97 if ( !$this->getOption( 'all' ) ) {
98 // If 'all' isn't passed as an option, just fall back to previous behaviour
99 // of using content namespaces
100 $where['page_namespace'] =
101 MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces();
102 }
103
104 // Mock request (hack, no real client)
105 $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip';
106
107 # Do remaining chunk
108 $end += $batchSize - 1;
109 $blockStart = $start;
110 $blockEnd = $start + $batchSize - 1;
111
112 $dbw = $this->getDB( DB_PRIMARY );
113 // Go through each page and save the output
114 while ( $blockEnd <= $end ) {
115 // Get the pages
116 $res = $dbr->select( 'page',
117 [ 'page_namespace', 'page_title', 'page_id' ],
118 $where + [ "page_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
119 __METHOD__,
120 [ 'ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY' ]
121 );
122
123 $this->beginTransaction( $dbw, __METHOD__ ); // for any changes
124 foreach ( $res as $row ) {
125 $rebuilt = false;
126
127 $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
128 if ( $title === null ) {
129 $this->output( "Page {$row->page_id} has bad title\n" );
130 continue; // broken title?
131 }
132
133 $context = new RequestContext();
134 $context->setTitle( $title );
135 $article = Article::newFromTitle( $title, $context );
136 $context->setWikiPage( $article->getPage() );
137
138 // Some extensions like FlaggedRevs while error out if this is unset
139 RequestContext::getMain()->setTitle( $title );
140
141 // If the article is cacheable, then load it
142 if ( $article->isFileCacheable( HTMLFileCache::MODE_REBUILD ) ) {
143 $viewCache = new HTMLFileCache( $title, 'view' );
144 $historyCache = new HTMLFileCache( $title, 'history' );
145 if ( $viewCache->isCacheGood() && $historyCache->isCacheGood() ) {
146 if ( $overwrite ) {
147 $rebuilt = true;
148 } else {
149 $this->output( "Page '$title' (id {$row->page_id}) already cached\n" );
150 continue; // done already!
151 }
152 }
153
154 AtEase::suppressWarnings(); // header notices
155
156 // 1. Cache ?action=view
157 // Be sure to reset the mocked request time (T24852)
158 $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
159 ob_start();
160 $article->view();
161 $context->getOutput()->output();
162 $context->getOutput()->clearHTML();
163 $viewHtml = ob_get_clean();
164 $viewCache->saveToFileCache( $viewHtml );
165
166 // 2. Cache ?action=history
167 // Be sure to reset the mocked request time (T24852)
168 $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
169 ob_start();
170 Action::factory( 'history', $article, $context )->show();
171 $context->getOutput()->output();
172 $context->getOutput()->clearHTML();
173 $historyHtml = ob_get_clean();
174 $historyCache->saveToFileCache( $historyHtml );
175
176 AtEase::restoreWarnings();
177
178 if ( $rebuilt ) {
179 $this->output( "Re-cached page '$title' (id {$row->page_id})..." );
180 } else {
181 $this->output( "Cached page '$title' (id {$row->page_id})..." );
182 }
183 $this->output( "[view: " . strlen( $viewHtml ) . " bytes; " .
184 "history: " . strlen( $historyHtml ) . " bytes]\n" );
185 } else {
186 $this->output( "Page '$title' (id {$row->page_id}) not cacheable\n" );
187 }
188 }
189 $this->commitTransaction( $dbw, __METHOD__ ); // commit any changes
190
191 $blockStart += $batchSize;
192 $blockEnd += $batchSize;
193 }
194 $this->output( "Done!\n" );
195 }
196}
197
198$maintClass = RebuildFileCache::class;
199require_once RUN_MAINTENANCE_IF_MAIN;
getDB()
Page view caching in the file system.
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
beginTransaction(IDatabase $dbw, $fname)
Begin a transaction on a DB.
commitTransaction(IDatabase $dbw, $fname)
Commit the transaction on a DB handle and wait for replica DBs to catch up.
output( $out, $channel=null)
Throw some output to the user.
hasOption( $name)
Checks to see if a particular option was set.
getBatchSize()
Returns batch size.
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.
setBatchSize( $s=0)
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Utility for loading settings files.
Maintenance script that builds the file cache.
execute()
Do the actual work.
finalSetup(SettingsBuilder $settingsBuilder=null)
Handle some last-minute setup here.
__construct()
Default constructor.
Group all the pieces relevant to the context of a request into one instance.
const DB_REPLICA
Definition defines.php:26
const DB_PRIMARY
Definition defines.php:28