MediaWiki
REL1_19
|
00001 <?php 00012 class ParserCache { 00013 private $mMemc; 00014 const try116cache = false; /* Only useful $wgParserCacheExpireTime after updating to 1.17 */ 00015 00021 public static function singleton() { 00022 static $instance; 00023 if ( !isset( $instance ) ) { 00024 global $parserMemc; 00025 $instance = new ParserCache( $parserMemc ); 00026 } 00027 return $instance; 00028 } 00029 00036 protected function __construct( $memCached ) { 00037 if ( !$memCached ) { 00038 throw new MWException( "Tried to create a ParserCache with an invalid memcached" ); 00039 } 00040 $this->mMemc = $memCached; 00041 } 00042 00048 protected function getParserOutputKey( $article, $hash ) { 00049 global $wgRequest; 00050 00051 // idhash seem to mean 'page id' + 'rendering hash' (r3710) 00052 $pageid = $article->getID(); 00053 $renderkey = (int)($wgRequest->getVal('action') == 'render'); 00054 00055 $key = wfMemcKey( 'pcache', 'idhash', "{$pageid}-{$renderkey}!{$hash}" ); 00056 return $key; 00057 } 00058 00063 protected function getOptionsKey( $article ) { 00064 $pageid = $article->getID(); 00065 return wfMemcKey( 'pcache', 'idoptions', "{$pageid}" ); 00066 } 00067 00081 function getETag( $article, $popts ) { 00082 return 'W/"' . $this->getParserOutputKey( $article, 00083 $popts->optionsHash( ParserOptions::legacyOptions(), $article->getTitle() ) ) . 00084 "--" . $article->getTouched() . '"'; 00085 } 00086 00093 public function getDirty( $article, $popts ) { 00094 $value = $this->get( $article, $popts, true ); 00095 return is_object( $value ) ? $value : false; 00096 } 00097 00108 public function getKey( $article, $popts, $useOutdated = true ) { 00109 global $wgCacheEpoch; 00110 00111 if( $popts instanceof User ) { 00112 wfWarn( "Use of outdated prototype ParserCache::getKey( &\$article, &\$user )\n" ); 00113 $popts = ParserOptions::newFromUser( $popts ); 00114 } 00115 00116 // Determine the options which affect this article 00117 $optionsKey = $this->mMemc->get( $this->getOptionsKey( $article ) ); 00118 if ( $optionsKey != false ) { 00119 if ( !$useOutdated && $optionsKey->expired( $article->getTouched() ) ) { 00120 wfIncrStats( "pcache_miss_expired" ); 00121 $cacheTime = $optionsKey->getCacheTime(); 00122 wfDebug( "Parser options key expired, touched " . $article->getTouched() . ", epoch $wgCacheEpoch, cached $cacheTime\n" ); 00123 return false; 00124 } 00125 00126 $usedOptions = $optionsKey->mUsedOptions; 00127 wfDebug( "Parser cache options found.\n" ); 00128 } else { 00129 if ( !$useOutdated && !self::try116cache ) { 00130 return false; 00131 } 00132 $usedOptions = ParserOptions::legacyOptions(); 00133 } 00134 00135 return $this->getParserOutputKey( $article, $popts->optionsHash( $usedOptions, $article->getTitle() ) ); 00136 } 00137 00148 public function get( $article, $popts, $useOutdated = false ) { 00149 global $wgCacheEpoch; 00150 wfProfileIn( __METHOD__ ); 00151 00152 $canCache = $article->checkTouched(); 00153 if ( !$canCache ) { 00154 // It's a redirect now 00155 wfProfileOut( __METHOD__ ); 00156 return false; 00157 } 00158 00159 $touched = $article->getTouched(); 00160 00161 $parserOutputKey = $this->getKey( $article, $popts, $useOutdated ); 00162 if ( $parserOutputKey === false ) { 00163 wfIncrStats( 'pcache_miss_absent' ); 00164 wfProfileOut( __METHOD__ ); 00165 return false; 00166 } 00167 00168 $value = $this->mMemc->get( $parserOutputKey ); 00169 if ( self::try116cache && !$value && strpos( $value, '*' ) !== -1 ) { 00170 wfDebug( "New format parser cache miss.\n" ); 00171 $parserOutputKey = $this->getParserOutputKey( $article, 00172 $popts->optionsHash( ParserOptions::legacyOptions(), $article->getTitle() ) ); 00173 $value = $this->mMemc->get( $parserOutputKey ); 00174 } 00175 if ( !$value ) { 00176 wfDebug( "ParserOutput cache miss.\n" ); 00177 wfIncrStats( "pcache_miss_absent" ); 00178 wfProfileOut( __METHOD__ ); 00179 return false; 00180 } 00181 00182 wfDebug( "ParserOutput cache found.\n" ); 00183 00184 // The edit section preference may not be the appropiate one in 00185 // the ParserOutput, as we are not storing it in the parsercache 00186 // key. Force it here. See bug 31445. 00187 $value->setEditSectionTokens( $popts->getEditSection() ); 00188 00189 if ( !$useOutdated && $value->expired( $touched ) ) { 00190 wfIncrStats( "pcache_miss_expired" ); 00191 $cacheTime = $value->getCacheTime(); 00192 wfDebug( "ParserOutput key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" ); 00193 $value = false; 00194 } else { 00195 wfIncrStats( "pcache_hit" ); 00196 } 00197 00198 wfProfileOut( __METHOD__ ); 00199 return $value; 00200 } 00201 00207 public function save( $parserOutput, $article, $popts ) { 00208 $expire = $parserOutput->getCacheExpiry(); 00209 00210 if( $expire > 0 ) { 00211 $now = wfTimestampNow(); 00212 00213 $optionsKey = new CacheTime; 00214 $optionsKey->mUsedOptions = $parserOutput->getUsedOptions(); 00215 $optionsKey->updateCacheExpiry( $expire ); 00216 00217 $optionsKey->setCacheTime( $now ); 00218 $parserOutput->setCacheTime( $now ); 00219 00220 $optionsKey->setContainsOldMagic( $parserOutput->containsOldMagic() ); 00221 00222 $parserOutputKey = $this->getParserOutputKey( $article, 00223 $popts->optionsHash( $optionsKey->mUsedOptions, $article->getTitle() ) ); 00224 00225 // Save the timestamp so that we don't have to load the revision row on view 00226 $parserOutput->setTimestamp( $article->getTimestamp() ); 00227 00228 $parserOutput->mText .= "\n<!-- Saved in parser cache with key $parserOutputKey and timestamp $now -->\n"; 00229 wfDebug( "Saved in parser cache with key $parserOutputKey and timestamp $now\n" ); 00230 00231 // Save the parser output 00232 $this->mMemc->set( $parserOutputKey, $parserOutput, $expire ); 00233 00234 // ...and its pointer 00235 $this->mMemc->set( $this->getOptionsKey( $article ), $optionsKey, $expire ); 00236 } else { 00237 wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" ); 00238 } 00239 } 00240 }