* @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 ) {
- 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();
- $parserOutputKey = $this->getKey( $article, $popts, $useOutdated );
+ $parserOutputKey = $this->getKey( $article, $popts,
+ $useOutdated ? self::USE_OUTDATED : self::USE_CURRENT_ONLY
+ );
if ( $parserOutputKey === false ) {
wfIncrStats( 'pcache.miss.absent' );
return false;
wfDebug( "ParserOutput cache found.\n" );
- // The edit section preference may not be the appropiate one in
- // the ParserOutput, as we are not storing it in the parsercache
- // key. Force it here. See T33445.
- $value->setEditSectionTokens( $popts->getEditSection() );
-
$wikiPage = method_exists( $article, 'getPage' )
? $article->getPage()
: $article;
$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" );
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;
+ }
}