MediaWiki
REL1_24
|
00001 <?php 00028 class ParserCache { 00030 private $mMemc; 00036 public static function singleton() { 00037 static $instance; 00038 if ( !isset( $instance ) ) { 00039 global $parserMemc; 00040 $instance = new ParserCache( $parserMemc ); 00041 } 00042 return $instance; 00043 } 00044 00052 protected function __construct( $memCached ) { 00053 if ( !$memCached ) { 00054 throw new MWException( "Tried to create a ParserCache with an invalid memcached" ); 00055 } 00056 $this->mMemc = $memCached; 00057 } 00058 00064 protected function getParserOutputKey( $article, $hash ) { 00065 global $wgRequest; 00066 00067 // idhash seem to mean 'page id' + 'rendering hash' (r3710) 00068 $pageid = $article->getID(); 00069 $renderkey = (int)( $wgRequest->getVal( 'action' ) == 'render' ); 00070 00071 $key = wfMemcKey( 'pcache', 'idhash', "{$pageid}-{$renderkey}!{$hash}" ); 00072 return $key; 00073 } 00074 00079 protected function getOptionsKey( $article ) { 00080 $pageid = $article->getID(); 00081 return wfMemcKey( 'pcache', 'idoptions', "{$pageid}" ); 00082 } 00083 00098 public function getETag( $article, $popts ) { 00099 return 'W/"' . $this->getParserOutputKey( $article, 00100 $popts->optionsHash( ParserOptions::legacyOptions(), $article->getTitle() ) ) . 00101 "--" . $article->getTouched() . '"'; 00102 } 00103 00110 public function getDirty( $article, $popts ) { 00111 $value = $this->get( $article, $popts, true ); 00112 return is_object( $value ) ? $value : false; 00113 } 00114 00134 public function getKey( $article, $popts, $useOutdated = true ) { 00135 global $wgCacheEpoch; 00136 00137 if ( $popts instanceof User ) { 00138 wfWarn( "Use of outdated prototype ParserCache::getKey( &\$article, &\$user )\n" ); 00139 $popts = ParserOptions::newFromUser( $popts ); 00140 } 00141 00142 // Determine the options which affect this article 00143 $optionsKey = $this->mMemc->get( $this->getOptionsKey( $article ) ); 00144 if ( $optionsKey != false ) { 00145 if ( !$useOutdated && $optionsKey->expired( $article->getTouched() ) ) { 00146 wfIncrStats( "pcache_miss_expired" ); 00147 $cacheTime = $optionsKey->getCacheTime(); 00148 wfDebug( "Parser options key expired, touched " . $article->getTouched() 00149 . ", epoch $wgCacheEpoch, cached $cacheTime\n" ); 00150 return false; 00151 } elseif ( $optionsKey->isDifferentRevision( $article->getLatest() ) ) { 00152 wfIncrStats( "pcache_miss_revid" ); 00153 $revId = $article->getLatest(); 00154 $cachedRevId = $optionsKey->getCacheRevisionId(); 00155 wfDebug( "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n" ); 00156 return false; 00157 } 00158 00159 // $optionsKey->mUsedOptions is set by save() by calling ParserOutput::getUsedOptions() 00160 $usedOptions = $optionsKey->mUsedOptions; 00161 wfDebug( "Parser cache options found.\n" ); 00162 } else { 00163 if ( !$useOutdated ) { 00164 return false; 00165 } 00166 $usedOptions = ParserOptions::legacyOptions(); 00167 } 00168 00169 return $this->getParserOutputKey( 00170 $article, 00171 $popts->optionsHash( $usedOptions, $article->getTitle() ) 00172 ); 00173 } 00174 00185 public function get( $article, $popts, $useOutdated = false ) { 00186 global $wgCacheEpoch; 00187 wfProfileIn( __METHOD__ ); 00188 00189 $canCache = $article->checkTouched(); 00190 if ( !$canCache ) { 00191 // It's a redirect now 00192 wfProfileOut( __METHOD__ ); 00193 return false; 00194 } 00195 00196 $touched = $article->getTouched(); 00197 00198 $parserOutputKey = $this->getKey( $article, $popts, $useOutdated ); 00199 if ( $parserOutputKey === false ) { 00200 wfIncrStats( 'pcache_miss_absent' ); 00201 wfProfileOut( __METHOD__ ); 00202 return false; 00203 } 00204 00205 $value = $this->mMemc->get( $parserOutputKey ); 00206 if ( !$value ) { 00207 wfDebug( "ParserOutput cache miss.\n" ); 00208 wfIncrStats( "pcache_miss_absent" ); 00209 wfProfileOut( __METHOD__ ); 00210 return false; 00211 } 00212 00213 wfDebug( "ParserOutput cache found.\n" ); 00214 00215 // The edit section preference may not be the appropiate one in 00216 // the ParserOutput, as we are not storing it in the parsercache 00217 // key. Force it here. See bug 31445. 00218 $value->setEditSectionTokens( $popts->getEditSection() ); 00219 00220 if ( !$useOutdated && $value->expired( $touched ) ) { 00221 wfIncrStats( "pcache_miss_expired" ); 00222 $cacheTime = $value->getCacheTime(); 00223 wfDebug( "ParserOutput key expired, touched $touched, " 00224 . "epoch $wgCacheEpoch, cached $cacheTime\n" ); 00225 $value = false; 00226 } elseif ( $value->isDifferentRevision( $article->getLatest() ) ) { 00227 wfIncrStats( "pcache_miss_revid" ); 00228 $revId = $article->getLatest(); 00229 $cachedRevId = $value->getCacheRevisionId(); 00230 wfDebug( "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n" ); 00231 $value = false; 00232 } else { 00233 wfIncrStats( "pcache_hit" ); 00234 } 00235 00236 wfProfileOut( __METHOD__ ); 00237 return $value; 00238 } 00239 00247 public function save( $parserOutput, $page, $popts, $cacheTime = null, $revId = null ) { 00248 $expire = $parserOutput->getCacheExpiry(); 00249 if ( $expire > 0 ) { 00250 $cacheTime = $cacheTime ?: wfTimestampNow(); 00251 if ( !$revId ) { 00252 $revision = $page->getRevision(); 00253 $revId = $revision ? $revision->getId() : null; 00254 } 00255 00256 $optionsKey = new CacheTime; 00257 $optionsKey->mUsedOptions = $parserOutput->getUsedOptions(); 00258 $optionsKey->updateCacheExpiry( $expire ); 00259 00260 $optionsKey->setCacheTime( $cacheTime ); 00261 $parserOutput->setCacheTime( $cacheTime ); 00262 $optionsKey->setCacheRevisionId( $revId ); 00263 $parserOutput->setCacheRevisionId( $revId ); 00264 00265 $optionsKey->setContainsOldMagic( $parserOutput->containsOldMagic() ); 00266 00267 $parserOutputKey = $this->getParserOutputKey( $page, 00268 $popts->optionsHash( $optionsKey->mUsedOptions, $page->getTitle() ) ); 00269 00270 // Save the timestamp so that we don't have to load the revision row on view 00271 $parserOutput->setTimestamp( $page->getTimestamp() ); 00272 00273 $msg = "Saved in parser cache with key $parserOutputKey" . 00274 " and timestamp $cacheTime" . 00275 " and revision id $revId" . 00276 "\n"; 00277 00278 $parserOutput->mText .= "\n<!-- $msg -->\n"; 00279 wfDebug( $msg ); 00280 00281 // Save the parser output 00282 $this->mMemc->set( $parserOutputKey, $parserOutput, $expire ); 00283 00284 // ...and its pointer 00285 $this->mMemc->set( $this->getOptionsKey( $page ), $optionsKey, $expire ); 00286 } else { 00287 wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" ); 00288 } 00289 } 00290 }