rebuildFileCache.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <?php
  2. /**
  3. * Build file cache for content pages
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. * http://www.gnu.org/copyleft/gpl.html
  19. *
  20. * @file
  21. * @ingroup Maintenance
  22. */
  23. require_once __DIR__ . '/Maintenance.php';
  24. /**
  25. * Maintenance script that builds file cache for content pages.
  26. *
  27. * @ingroup Maintenance
  28. */
  29. class RebuildFileCache extends Maintenance {
  30. private $enabled = true;
  31. public function __construct() {
  32. parent::__construct();
  33. $this->addDescription( 'Build file cache for content pages' );
  34. $this->addOption( 'start', 'Page_id to start from', false, true );
  35. $this->addOption( 'end', 'Page_id to end on', false, true );
  36. $this->addOption( 'overwrite', 'Refresh page cache' );
  37. $this->setBatchSize( 100 );
  38. }
  39. public function finalSetup() {
  40. global $wgDebugToolbar, $wgUseFileCache, $wgReadOnly;
  41. $this->enabled = $wgUseFileCache;
  42. // Script will handle capturing output and saving it itself
  43. $wgUseFileCache = false;
  44. // Debug toolbar makes content uncacheable so we disable it.
  45. // Has to be done before Setup.php initialize MWDebug
  46. $wgDebugToolbar = false;
  47. // Avoid DB writes (like enotif/counters)
  48. $wgReadOnly = 'Building cache'; // avoid DB writes (like enotif/counters)
  49. parent::finalSetup();
  50. }
  51. public function execute() {
  52. global $wgRequestTime;
  53. if ( !$this->enabled ) {
  54. $this->error( "Nothing to do -- \$wgUseFileCache is disabled.", true );
  55. }
  56. $start = $this->getOption( 'start', "0" );
  57. if ( !ctype_digit( $start ) ) {
  58. $this->error( "Invalid value for start parameter.", true );
  59. }
  60. $start = intval( $start );
  61. $end = $this->getOption( 'end', "0" );
  62. if ( !ctype_digit( $end ) ) {
  63. $this->error( "Invalid value for end parameter.", true );
  64. }
  65. $end = intval( $end );
  66. $this->output( "Building content page file cache from page {$start}!\n" );
  67. $dbr = $this->getDB( DB_REPLICA );
  68. $overwrite = $this->getOption( 'overwrite', false );
  69. $start = ( $start > 0 )
  70. ? $start
  71. : $dbr->selectField( 'page', 'MIN(page_id)', false, __METHOD__ );
  72. $end = ( $end > 0 )
  73. ? $end
  74. : $dbr->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
  75. if ( !$start ) {
  76. $this->error( "Nothing to do.", true );
  77. }
  78. $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client
  79. # Do remaining chunk
  80. $end += $this->mBatchSize - 1;
  81. $blockStart = $start;
  82. $blockEnd = $start + $this->mBatchSize - 1;
  83. $dbw = $this->getDB( DB_MASTER );
  84. // Go through each page and save the output
  85. while ( $blockEnd <= $end ) {
  86. // Get the pages
  87. $res = $dbr->select( 'page',
  88. [ 'page_namespace', 'page_title', 'page_id' ],
  89. [ 'page_namespace' => MWNamespace::getContentNamespaces(),
  90. "page_id BETWEEN $blockStart AND $blockEnd" ],
  91. __METHOD__,
  92. [ 'ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY' ]
  93. );
  94. $this->beginTransaction( $dbw, __METHOD__ ); // for any changes
  95. foreach ( $res as $row ) {
  96. $rebuilt = false;
  97. $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
  98. if ( null == $title ) {
  99. $this->output( "Page {$row->page_id} has bad title\n" );
  100. continue; // broken title?
  101. }
  102. $context = new RequestContext();
  103. $context->setTitle( $title );
  104. $article = Article::newFromTitle( $title, $context );
  105. $context->setWikiPage( $article->getPage() );
  106. // If the article is cacheable, then load it
  107. if ( $article->isFileCacheable( HTMLFileCache::MODE_REBUILD ) ) {
  108. $viewCache = new HTMLFileCache( $title, 'view' );
  109. $historyCache = new HTMLFileCache( $title, 'history' );
  110. if ( $viewCache->isCacheGood() && $historyCache->isCacheGood() ) {
  111. if ( $overwrite ) {
  112. $rebuilt = true;
  113. } else {
  114. $this->output( "Page '$title' (id {$row->page_id}) already cached\n" );
  115. continue; // done already!
  116. }
  117. }
  118. MediaWiki\suppressWarnings(); // header notices
  119. // Cache ?action=view
  120. $wgRequestTime = microtime( true ); # bug 22852
  121. ob_start();
  122. $article->view();
  123. $context->getOutput()->output();
  124. $context->getOutput()->clearHTML();
  125. $viewHtml = ob_get_clean();
  126. $viewCache->saveToFileCache( $viewHtml );
  127. // Cache ?action=history
  128. $wgRequestTime = microtime( true ); # bug 22852
  129. ob_start();
  130. Action::factory( 'history', $article, $context )->show();
  131. $context->getOutput()->output();
  132. $context->getOutput()->clearHTML();
  133. $historyHtml = ob_get_clean();
  134. $historyCache->saveToFileCache( $historyHtml );
  135. MediaWiki\restoreWarnings();
  136. if ( $rebuilt ) {
  137. $this->output( "Re-cached page '$title' (id {$row->page_id})..." );
  138. } else {
  139. $this->output( "Cached page '$title' (id {$row->page_id})..." );
  140. }
  141. $this->output( "[view: " . strlen( $viewHtml ) . " bytes; " .
  142. "history: " . strlen( $historyHtml ) . " bytes]\n" );
  143. } else {
  144. $this->output( "Page '$title' (id {$row->page_id}) not cacheable\n" );
  145. }
  146. }
  147. $this->commitTransaction( $dbw, __METHOD__ ); // commit any changes (just for sanity)
  148. $blockStart += $this->mBatchSize;
  149. $blockEnd += $this->mBatchSize;
  150. }
  151. $this->output( "Done!\n" );
  152. }
  153. }
  154. $maintClass = "RebuildFileCache";
  155. require_once RUN_MAINTENANCE_IF_MAIN;