MediaWiki REL1_34
ParserCache.php
Go to the documentation of this file.
1<?php
25
38
40 const USE_EXPIRED = 1;
41
43 const USE_OUTDATED = 2;
44
49 const USE_ANYTHING = 3;
50
52 private $cache;
53
59 private $cacheEpoch;
60
67 public static function singleton() {
68 return MediaWikiServices::getInstance()->getParserCache();
69 }
70
81 public function __construct( BagOStuff $cache, $cacheEpoch = '20030516000000' ) {
82 $this->cache = $cache;
83 $this->cacheEpoch = $cacheEpoch;
84 }
85
91 protected function getParserOutputKey( $article, $hash ) {
92 global $wgRequest;
93
94 // idhash seem to mean 'page id' + 'rendering hash' (r3710)
95 $pageid = $article->getId();
96 $renderkey = (int)( $wgRequest->getVal( 'action' ) == 'render' );
97
98 $key = $this->cache->makeKey( 'pcache', 'idhash', "{$pageid}-{$renderkey}!{$hash}" );
99 return $key;
100 }
101
106 protected function getOptionsKey( $page ) {
107 return $this->cache->makeKey( 'pcache', 'idoptions', $page->getId() );
108 }
109
114 public function deleteOptionsKey( $page ) {
115 $this->cache->delete( $this->getOptionsKey( $page ) );
116 }
117
132 public function getETag( $article, $popts ) {
133 return 'W/"' . $this->getParserOutputKey( $article,
134 $popts->optionsHash( ParserOptions::allCacheVaryingOptions(), $article->getTitle() ) ) .
135 "--" . $article->getTouched() . '"';
136 }
137
144 public function getDirty( $article, $popts ) {
145 $value = $this->get( $article, $popts, true );
146 return is_object( $value ) ? $value : false;
147 }
148
153 private function incrementStats( $article, $metricSuffix ) {
154 // old style global metric (can be removed once no longer used)
155 wfIncrStats( 'pcache.' . $metricSuffix );
156 // new per content model metric
157 $contentModel = str_replace( '.', '_', $article->getContentModel() );
158 $metricSuffix = str_replace( '.', '_', $metricSuffix );
159 wfIncrStats( 'pcache.' . $contentModel . '.' . $metricSuffix );
160 }
161
182 public function getKey( $article, $popts, $useOutdated = self::USE_ANYTHING ) {
183 if ( is_bool( $useOutdated ) ) {
184 $useOutdated = $useOutdated ? self::USE_ANYTHING : self::USE_CURRENT_ONLY;
185 }
186
187 if ( $popts instanceof User ) {
188 wfWarn( "Use of outdated prototype ParserCache::getKey( &\$article, &\$user )\n" );
189 $popts = ParserOptions::newFromUser( $popts );
190 }
191
192 // Determine the options which affect this article
193 $optionsKey = $this->cache->get(
194 $this->getOptionsKey( $article ), BagOStuff::READ_VERIFIED );
195 if ( $optionsKey instanceof CacheTime ) {
196 if ( $useOutdated < self::USE_EXPIRED && $optionsKey->expired( $article->getTouched() ) ) {
197 $this->incrementStats( $article, "miss.expired" );
198 $cacheTime = $optionsKey->getCacheTime();
199 wfDebugLog( "ParserCache",
200 "Parser options key expired, touched " . $article->getTouched()
201 . ", epoch {$this->cacheEpoch}, cached $cacheTime\n" );
202 return false;
203 } elseif ( $useOutdated < self::USE_OUTDATED &&
204 $optionsKey->isDifferentRevision( $article->getLatest() )
205 ) {
206 $this->incrementStats( $article, "miss.revid" );
207 $revId = $article->getLatest();
208 $cachedRevId = $optionsKey->getCacheRevisionId();
209 wfDebugLog( "ParserCache",
210 "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n"
211 );
212 return false;
213 }
214
215 // $optionsKey->mUsedOptions is set by save() by calling ParserOutput::getUsedOptions()
216 $usedOptions = $optionsKey->mUsedOptions;
217 wfDebug( "Parser cache options found.\n" );
218 } else {
219 if ( $useOutdated < self::USE_ANYTHING ) {
220 return false;
221 }
222 $usedOptions = ParserOptions::allCacheVaryingOptions();
223 }
224
225 return $this->getParserOutputKey(
226 $article,
227 $popts->optionsHash( $usedOptions, $article->getTitle() )
228 );
229 }
230
241 public function get( $article, $popts, $useOutdated = false ) {
242 $canCache = $article->checkTouched();
243 if ( !$canCache ) {
244 // It's a redirect now
245 return false;
246 }
247
248 $touched = $article->getTouched();
249
250 $parserOutputKey = $this->getKey( $article, $popts,
251 $useOutdated ? self::USE_OUTDATED : self::USE_CURRENT_ONLY
252 );
253 if ( $parserOutputKey === false ) {
254 $this->incrementStats( $article, 'miss.absent' );
255 return false;
256 }
257
258 $casToken = null;
260 $value = $this->cache->get( $parserOutputKey, BagOStuff::READ_VERIFIED );
261 if ( !$value ) {
262 wfDebug( "ParserOutput cache miss.\n" );
263 $this->incrementStats( $article, "miss.absent" );
264 return false;
265 }
266
267 wfDebug( "ParserOutput cache found.\n" );
268
269 $wikiPage = method_exists( $article, 'getPage' )
270 ? $article->getPage()
271 : $article;
272
273 if ( !$useOutdated && $value->expired( $touched ) ) {
274 $this->incrementStats( $article, "miss.expired" );
275 $cacheTime = $value->getCacheTime();
276 wfDebugLog( "ParserCache",
277 "ParserOutput key expired, touched $touched, "
278 . "epoch {$this->cacheEpoch}, cached $cacheTime\n" );
279 $value = false;
280 } elseif ( !$useOutdated && $value->isDifferentRevision( $article->getLatest() ) ) {
281 $this->incrementStats( $article, "miss.revid" );
282 $revId = $article->getLatest();
283 $cachedRevId = $value->getCacheRevisionId();
284 wfDebugLog( "ParserCache",
285 "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n"
286 );
287 $value = false;
288 } elseif (
289 Hooks::run( 'RejectParserCacheValue', [ $value, $wikiPage, $popts ] ) === false
290 ) {
291 $this->incrementStats( $article, 'miss.rejected' );
292 wfDebugLog( "ParserCache",
293 "ParserOutput key valid, but rejected by RejectParserCacheValue hook handler.\n"
294 );
295 $value = false;
296 } else {
297 $this->incrementStats( $article, "hit" );
298 }
299
300 return $value;
301 }
302
310 public function save(
311 ParserOutput $parserOutput,
312 $page,
313 $popts,
314 $cacheTime = null,
315 $revId = null
316 ) {
317 if ( !$parserOutput->hasText() ) {
318 throw new InvalidArgumentException( 'Attempt to cache a ParserOutput with no text set!' );
319 }
320
321 $expire = $parserOutput->getCacheExpiry();
322 if ( $expire > 0 && !$this->cache instanceof EmptyBagOStuff ) {
323 $cacheTime = $cacheTime ?: wfTimestampNow();
324 if ( !$revId ) {
325 $revision = $page->getRevision();
326 $revId = $revision ? $revision->getId() : null;
327 }
328
329 $optionsKey = new CacheTime;
330 $optionsKey->mUsedOptions = $parserOutput->getUsedOptions();
331 $optionsKey->updateCacheExpiry( $expire );
332
333 $optionsKey->setCacheTime( $cacheTime );
334 $parserOutput->setCacheTime( $cacheTime );
335 $optionsKey->setCacheRevisionId( $revId );
336 $parserOutput->setCacheRevisionId( $revId );
337
338 $parserOutputKey = $this->getParserOutputKey( $page,
339 $popts->optionsHash( $optionsKey->mUsedOptions, $page->getTitle() ) );
340
341 // Save the timestamp so that we don't have to load the revision row on view
342 $parserOutput->setTimestamp( $page->getTimestamp() );
343
344 $msg = "Saved in parser cache with key $parserOutputKey" .
345 " and timestamp $cacheTime" .
346 " and revision id $revId" .
347 "\n";
348
349 $parserOutput->mText .= "\n<!-- $msg -->\n";
350 wfDebug( $msg );
351
352 // Save the parser output
353 $this->cache->set(
354 $parserOutputKey,
355 $parserOutput,
356 $expire,
357 BagOStuff::WRITE_ALLOW_SEGMENTS
358 );
359
360 // ...and its pointer
361 $this->cache->set( $this->getOptionsKey( $page ), $optionsKey, $expire );
362
363 Hooks::run(
364 'ParserCacheSaveComplete',
365 [ $this, $parserOutput, $page->getTitle(), $popts, $revId ]
366 );
367 } elseif ( $expire <= 0 ) {
368 wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
369 }
370 }
371
379 public function getCacheStorage() {
380 return $this->cache;
381 }
382}
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfIncrStats( $key, $count=1)
Increment a statistics counter.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
if(! $wgDBerrorLogTZ) $wgRequest
Definition Setup.php:751
Class representing a cache/ephemeral data store.
Definition BagOStuff.php:63
Parser cache specific expiry check.
Definition CacheTime.php:29
setCacheRevisionId( $id)
Definition CacheTime.php:95
setCacheTime( $t)
setCacheTime() sets the timestamp expressing when the page has been rendered.
Definition CacheTime.php:74
getCacheExpiry()
Returns the number of seconds after which this object should expire.
A BagOStuff object with no objects in it.
MediaWikiServices is the service locator for the application scope of MediaWiki.
save(ParserOutput $parserOutput, $page, $popts, $cacheTime=null, $revId=null)
getDirty( $article, $popts)
Retrieve the ParserOutput from ParserCache, even if it's outdated.
getParserOutputKey( $article, $hash)
const USE_EXPIRED
Use expired data if current data is unavailable.
deleteOptionsKey( $page)
getOptionsKey( $page)
__construct(BagOStuff $cache, $cacheEpoch='20030516000000')
Setup a cache pathway with a given back-end storage mechanism.
static singleton()
Get an instance of this object.
getCacheStorage()
Get the backend BagOStuff instance that powers the parser cache.
const USE_ANYTHING
Use expired data and data from different revisions, and if all else fails vary on all variable option...
string $cacheEpoch
Anything cached prior to this is invalidated.
const USE_CURRENT_ONLY
Constants for self::getKey()
getKey( $article, $popts, $useOutdated=self::USE_ANYTHING)
Generates a key for caching the given article considering the given parser options.
incrementStats( $article, $metricSuffix)
const USE_OUTDATED
Use expired data or data from different revisions if current data is unavailable.
BagOStuff $cache
getETag( $article, $popts)
Provides an E-Tag suitable for the whole page.
hasText()
Returns true if text was passed to the constructor, or set using setText().
getUsedOptions()
Returns the options from its ParserOptions which have been taken into account to produce this output.
setTimestamp( $timestamp)
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:51
$cache
Definition mcc.php:33
return true
Definition router.php:94