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