* @ingroup Cache Parser
*/
+use MediaWiki\MediaWikiServices;
+
/**
* @ingroup Cache Parser
* @todo document
*/
class ParserCache {
+ /**
+ * Constants for self::getKey()
+ * @since 1.30
+ */
+
+ /** Use only current data */
+ const USE_CURRENT_ONLY = 0;
+
+ /** Use expired data if current data is unavailable */
+ const USE_EXPIRED = 1;
+
+ /** Use expired data or data from different revisions if current data is unavailable */
+ const USE_OUTDATED = 2;
+
+ /**
+ * Use expired data and data from different revisions, and if all else
+ * fails vary on all variable options
+ */
+ const USE_ANYTHING = 3;
+
/** @var BagOStuff */
private $mMemc;
+
+ /**
+ * Anything cached prior to this is invalidated
+ *
+ * @var string
+ */
+ private $cacheEpoch;
/**
* Get an instance of this object
*
+ * @deprecated since 1.30, use MediaWikiServices instead
* @return ParserCache
*/
public static function singleton() {
- static $instance;
- if ( !isset( $instance ) ) {
- global $parserMemc;
- $instance = new ParserCache( $parserMemc );
- }
- return $instance;
+ return MediaWikiServices::getInstance()->getParserCache();
}
/**
* This class use an invalidation strategy that is compatible with
* MultiWriteBagOStuff in async replication mode.
*
- * @param BagOStuff $memCached
+ * @param BagOStuff $cache
+ * @param string $cacheEpoch Anything before this timestamp is invalidated
* @throws MWException
*/
- protected function __construct( BagOStuff $memCached ) {
- $this->mMemc = $memCached;
+ public function __construct( BagOStuff $cache, $cacheEpoch = '20030516000000' ) {
+ $this->mMemc = $cache;
+ $this->cacheEpoch = $cacheEpoch;
}
/**
*/
public function getETag( $article, $popts ) {
return 'W/"' . $this->getParserOutputKey( $article,
- $popts->optionsHash( ParserOptions::legacyOptions(), $article->getTitle() ) ) .
+ $popts->optionsHash( ParserOptions::allCacheVaryingOptions(), $article->getTitle() ) ) .
"--" . $article->getTouched() . '"';
}
* It would be preferable to have this code in get()
* instead of having Article looking in our internals.
*
- * @todo Document parameter $useOutdated
- *
* @param WikiPage $article
* @param ParserOptions $popts
- * @param bool $useOutdated (default true)
+ * @param int|bool $useOutdated One of the USE constants. For backwards
+ * compatibility, boolean false is treated as USE_CURRENT_ONLY and
+ * boolean true is treated as USE_ANYTHING.
* @return bool|mixed|string
+ * @since 1.30 Changed $useOutdated to an int and added the non-boolean values
*/
- public function getKey( $article, $popts, $useOutdated = true ) {
- $dummy = null;
- return $this->getKeyReal( $article, $popts, $useOutdated, $dummy );
- }
-
- /**
- * Temporary internal function to allow accessing $usedOptions
- * @todo Merge this back to self::getKey() when ParserOptions::optionsHashPre30() is removed
- * @param WikiPage $article
- * @param ParserOptions $popts
- * @param bool $useOutdated (default true)
- * @param array &$usedOptions Don't use this, it will go away soon
- * @return bool|mixed|string
- */
- private function getKeyReal( $article, $popts, $useOutdated, &$usedOptions ) {
- global $wgCacheEpoch;
+ public function getKey( $article, $popts, $useOutdated = self::USE_ANYTHING ) {
+ if ( is_bool( $useOutdated ) ) {
+ $useOutdated = $useOutdated ? self::USE_ANYTHING : self::USE_CURRENT_ONLY;
+ }
if ( $popts instanceof User ) {
wfWarn( "Use of outdated prototype ParserCache::getKey( &\$article, &\$user )\n" );
$optionsKey = $this->mMemc->get(
$this->getOptionsKey( $article ), $casToken, BagOStuff::READ_VERIFIED );
if ( $optionsKey instanceof CacheTime ) {
- if ( !$useOutdated && $optionsKey->expired( $article->getTouched() ) ) {
+ if ( $useOutdated < self::USE_EXPIRED && $optionsKey->expired( $article->getTouched() ) ) {
wfIncrStats( "pcache.miss.expired" );
$cacheTime = $optionsKey->getCacheTime();
wfDebugLog( "ParserCache",
"Parser options key expired, touched " . $article->getTouched()
- . ", epoch $wgCacheEpoch, cached $cacheTime\n" );
+ . ", epoch {$this->cacheEpoch}, cached $cacheTime\n" );
return false;
- } elseif ( !$useOutdated && $optionsKey->isDifferentRevision( $article->getLatest() ) ) {
+ } elseif ( $useOutdated < self::USE_OUTDATED &&
+ $optionsKey->isDifferentRevision( $article->getLatest() )
+ ) {
wfIncrStats( "pcache.miss.revid" );
$revId = $article->getLatest();
$cachedRevId = $optionsKey->getCacheRevisionId();
$usedOptions = $optionsKey->mUsedOptions;
wfDebug( "Parser cache options found.\n" );
} else {
- if ( !$useOutdated ) {
+ if ( $useOutdated < self::USE_ANYTHING ) {
return false;
}
- $usedOptions = ParserOptions::legacyOptions();
+ $usedOptions = ParserOptions::allCacheVaryingOptions();
}
return $this->getParserOutputKey(
* @return ParserOutput|bool False on failure
*/
public function get( $article, $popts, $useOutdated = false ) {
- global $wgCacheEpoch;
-
$canCache = $article->checkTouched();
if ( !$canCache ) {
// It's a redirect now
$touched = $article->getTouched();
- $usedOptions = null;
- $parserOutputKey = $this->getKeyReal( $article, $popts, $useOutdated, $usedOptions );
+ $parserOutputKey = $this->getKey( $article, $popts,
+ $useOutdated ? self::USE_OUTDATED : self::USE_CURRENT_ONLY
+ );
if ( $parserOutputKey === false ) {
wfIncrStats( 'pcache.miss.absent' );
return false;
$casToken = null;
/** @var ParserOutput $value */
$value = $this->mMemc->get( $parserOutputKey, $casToken, BagOStuff::READ_VERIFIED );
- if ( !$value ) {
- $parserOutputKey = $this->getParserOutputKey(
- $article,
- $popts->optionsHashPre30( $usedOptions, $article->getTitle() )
- );
- $value = $this->mMemc->get( $parserOutputKey, $casToken, BagOStuff::READ_VERIFIED );
- }
if ( !$value ) {
wfDebug( "ParserOutput cache miss.\n" );
wfIncrStats( "pcache.miss.absent" );
$cacheTime = $value->getCacheTime();
wfDebugLog( "ParserCache",
"ParserOutput key expired, touched $touched, "
- . "epoch $wgCacheEpoch, cached $cacheTime\n" );
+ . "epoch {$this->cacheEpoch}, cached $cacheTime\n" );
$value = false;
} elseif ( !$useOutdated && $value->isDifferentRevision( $article->getLatest() ) ) {
wfIncrStats( "pcache.miss.revid" );
// ...and its pointer
$this->mMemc->set( $this->getOptionsKey( $page ), $optionsKey, $expire );
- // Normally, when there was no key change, the above would have
- // overwritten the old entry. Delete that old entry to save disk
- // space.
- $oldParserOutputKey = $this->getParserOutputKey( $page,
- $popts->optionsHashPre30( $optionsKey->mUsedOptions, $page->getTitle() ) );
- $this->mMemc->delete( $oldParserOutputKey );
-
Hooks::run(
'ParserCacheSaveComplete',
[ $this, $parserOutput, $page->getTitle(), $popts, $revId ]
wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
}
}
+
+ /**
+ * Get the backend BagOStuff instance that
+ * powers the parser cache
+ *
+ * @since 1.30
+ * @return BagOStuff
+ */
+ public function getCacheStorage() {
+ return $this->mMemc;
+ }
}