MediaWiki  master
rebuildFileCache.php
Go to the documentation of this file.
1 <?php
25 
26 require_once __DIR__ . '/Maintenance.php';
27 
34  private $enabled = true;
35 
36  public function __construct() {
37  parent::__construct();
38  $this->addDescription( 'Build file cache for content pages' );
39  $this->addOption( 'start', 'Page_id to start from', false, true );
40  $this->addOption( 'end', 'Page_id to end on', false, true );
41  $this->addOption( 'overwrite', 'Refresh page cache' );
42  $this->setBatchSize( 100 );
43  }
44 
45  public function finalSetup() {
46  global $wgUseFileCache;
47 
48  $this->enabled = $wgUseFileCache;
49  // Script will handle capturing output and saving it itself
50  $wgUseFileCache = false;
51  // Avoid DB writes (like enotif/counters)
52  MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()
53  ->setReason( 'Building cache' );
54 
55  // Ensure no debug-specific logic ends up in the cache (must be after Setup.php)
57 
58  parent::finalSetup();
59  }
60 
61  public function execute() {
62  if ( !$this->enabled ) {
63  $this->fatalError( "Nothing to do -- \$wgUseFileCache is disabled." );
64  }
65 
66  $start = $this->getOption( 'start', "0" );
67  if ( !ctype_digit( $start ) ) {
68  $this->fatalError( "Invalid value for start parameter." );
69  }
70  $start = intval( $start );
71 
72  $end = $this->getOption( 'end', "0" );
73  if ( !ctype_digit( $end ) ) {
74  $this->fatalError( "Invalid value for end parameter." );
75  }
76  $end = intval( $end );
77 
78  $this->output( "Building content page file cache from page {$start}!\n" );
79 
80  $dbr = $this->getDB( DB_REPLICA );
81  $batchSize = $this->getBatchSize();
82  $overwrite = $this->hasOption( 'overwrite' );
83  $start = ( $start > 0 )
84  ? $start
85  : $dbr->selectField( 'page', 'MIN(page_id)', '', __METHOD__ );
86  $end = ( $end > 0 )
87  ? $end
88  : $dbr->selectField( 'page', 'MAX(page_id)', '', __METHOD__ );
89  if ( !$start ) {
90  $this->fatalError( "Nothing to do." );
91  }
92 
93  // Mock request (hack, no real client)
94  $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip';
95 
96  # Do remaining chunk
97  $end += $batchSize - 1;
98  $blockStart = $start;
99  $blockEnd = $start + $batchSize - 1;
100 
101  $dbw = $this->getDB( DB_MASTER );
102  // Go through each page and save the output
103  while ( $blockEnd <= $end ) {
104  // Get the pages
105  $res = $dbr->select( 'page',
106  [ 'page_namespace', 'page_title', 'page_id' ],
107  [ 'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
108  getContentNamespaces(),
109  "page_id BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
110  __METHOD__,
111  [ 'ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY' ]
112  );
113 
114  $this->beginTransaction( $dbw, __METHOD__ ); // for any changes
115  foreach ( $res as $row ) {
116  $rebuilt = false;
117 
118  $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
119  if ( $title === null ) {
120  $this->output( "Page {$row->page_id} has bad title\n" );
121  continue; // broken title?
122  }
123 
124  $context = new RequestContext();
125  $context->setTitle( $title );
126  $article = Article::newFromTitle( $title, $context );
127  $context->setWikiPage( $article->getPage() );
128 
129  // Some extensions like FlaggedRevs while error out if this is unset
130  RequestContext::getMain()->setTitle( $title );
131 
132  // If the article is cacheable, then load it
133  if ( $article->isFileCacheable( HTMLFileCache::MODE_REBUILD ) ) {
134  $viewCache = new HTMLFileCache( $title, 'view' );
135  $historyCache = new HTMLFileCache( $title, 'history' );
136  if ( $viewCache->isCacheGood() && $historyCache->isCacheGood() ) {
137  if ( $overwrite ) {
138  $rebuilt = true;
139  } else {
140  $this->output( "Page '$title' (id {$row->page_id}) already cached\n" );
141  continue; // done already!
142  }
143  }
144 
145  Wikimedia\suppressWarnings(); // header notices
146 
147  // 1. Cache ?action=view
148  // Be sure to reset the mocked request time (T24852)
149  $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
150  ob_start();
151  $article->view();
152  $context->getOutput()->output();
153  $context->getOutput()->clearHTML();
154  $viewHtml = ob_get_clean();
155  $viewCache->saveToFileCache( $viewHtml );
156 
157  // 2. Cache ?action=history
158  // Be sure to reset the mocked request time (T24852)
159  $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
160  ob_start();
161  Action::factory( 'history', $article, $context )->show();
162  $context->getOutput()->output();
163  $context->getOutput()->clearHTML();
164  $historyHtml = ob_get_clean();
165  $historyCache->saveToFileCache( $historyHtml );
166 
167  Wikimedia\restoreWarnings();
168 
169  if ( $rebuilt ) {
170  $this->output( "Re-cached page '$title' (id {$row->page_id})..." );
171  } else {
172  $this->output( "Cached page '$title' (id {$row->page_id})..." );
173  }
174  $this->output( "[view: " . strlen( $viewHtml ) . " bytes; " .
175  "history: " . strlen( $historyHtml ) . " bytes]\n" );
176  } else {
177  $this->output( "Page '$title' (id {$row->page_id}) not cacheable\n" );
178  }
179  }
180  $this->commitTransaction( $dbw, __METHOD__ ); // commit any changes (just for sanity)
181 
182  $blockStart += $batchSize;
183  $blockEnd += $batchSize;
184  }
185  $this->output( "Done!\n" );
186  }
187 }
188 
189 $maintClass = RebuildFileCache::class;
190 require_once RUN_MAINTENANCE_IF_MAIN;
commitTransaction(IDatabase $dbw, $fname)
Commit the transcation on a DB handle and wait for replica DBs to catch up.
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:39
$context
Definition: load.php:45
getOption( $name, $default=null)
Get an option, or return the default.
Maintenance script that builds file cache for content pages.
static factory( $action, Page $page, IContextSource $context=null)
Get an appropriate Action subclass for the given action.
Definition: Action.php:97
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: Maintenance.php:86
Page view caching in the file system.
setBatchSize( $s=0)
Set the batch size.
static getInstance()
Returns the global default instance of the top level service locator.
hasOption( $name)
Checks to see if a particular option exists.
const DB_MASTER
Definition: defines.php:26
static getMain()
Get the RequestContext object associated with the main request.
$wgUseFileCache
This will cache static pages for non-logged-in users to reduce database traffic on public sites...
addDescription( $text)
Set the description text.
output( $out, $channel=null)
Throw some output to the user.
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:610
getBatchSize()
Returns batch size.
static deinit()
Disable the debugger.
Definition: MWDebug.php:109
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
const DB_REPLICA
Definition: defines.php:25
static newFromTitle( $title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Definition: Article.php:163
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
getDB( $db, $groups=[], $dbDomain=false)
Returns a database to be used by current maintenance script.
beginTransaction(IDatabase $dbw, $fname)
Begin a transcation on a DB.