MediaWiki
REL1_20
|
00001 <?php 00028 class ParserCache { 00029 private $mMemc; 00030 const try116cache = false; /* Only useful $wgParserCacheExpireTime after updating to 1.17 */ 00031 00037 public static function singleton() { 00038 static $instance; 00039 if ( !isset( $instance ) ) { 00040 global $parserMemc; 00041 $instance = new ParserCache( $parserMemc ); 00042 } 00043 return $instance; 00044 } 00045 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 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 00127 public function getKey( $article, $popts, $useOutdated = true ) { 00128 global $wgCacheEpoch; 00129 00130 if( $popts instanceof User ) { 00131 wfWarn( "Use of outdated prototype ParserCache::getKey( &\$article, &\$user )\n" ); 00132 $popts = ParserOptions::newFromUser( $popts ); 00133 } 00134 00135 // Determine the options which affect this article 00136 $optionsKey = $this->mMemc->get( $this->getOptionsKey( $article ) ); 00137 if ( $optionsKey != false ) { 00138 if ( !$useOutdated && $optionsKey->expired( $article->getTouched() ) ) { 00139 wfIncrStats( "pcache_miss_expired" ); 00140 $cacheTime = $optionsKey->getCacheTime(); 00141 wfDebug( "Parser options key expired, touched " . $article->getTouched() . ", epoch $wgCacheEpoch, cached $cacheTime\n" ); 00142 return false; 00143 } 00144 00145 $usedOptions = $optionsKey->mUsedOptions; 00146 wfDebug( "Parser cache options found.\n" ); 00147 } else { 00148 if ( !$useOutdated && !self::try116cache ) { 00149 return false; 00150 } 00151 $usedOptions = ParserOptions::legacyOptions(); 00152 } 00153 00154 return $this->getParserOutputKey( $article, $popts->optionsHash( $usedOptions, $article->getTitle() ) ); 00155 } 00156 00167 public function get( $article, $popts, $useOutdated = false ) { 00168 global $wgCacheEpoch; 00169 wfProfileIn( __METHOD__ ); 00170 00171 $canCache = $article->checkTouched(); 00172 if ( !$canCache ) { 00173 // It's a redirect now 00174 wfProfileOut( __METHOD__ ); 00175 return false; 00176 } 00177 00178 $touched = $article->getTouched(); 00179 00180 $parserOutputKey = $this->getKey( $article, $popts, $useOutdated ); 00181 if ( $parserOutputKey === false ) { 00182 wfIncrStats( 'pcache_miss_absent' ); 00183 wfProfileOut( __METHOD__ ); 00184 return false; 00185 } 00186 00187 $value = $this->mMemc->get( $parserOutputKey ); 00188 if ( self::try116cache && !$value && strpos( $value, '*' ) !== -1 ) { 00189 wfDebug( "New format parser cache miss.\n" ); 00190 $parserOutputKey = $this->getParserOutputKey( $article, 00191 $popts->optionsHash( ParserOptions::legacyOptions(), $article->getTitle() ) ); 00192 $value = $this->mMemc->get( $parserOutputKey ); 00193 } 00194 if ( !$value ) { 00195 wfDebug( "ParserOutput cache miss.\n" ); 00196 wfIncrStats( "pcache_miss_absent" ); 00197 wfProfileOut( __METHOD__ ); 00198 return false; 00199 } 00200 00201 wfDebug( "ParserOutput cache found.\n" ); 00202 00203 // The edit section preference may not be the appropiate one in 00204 // the ParserOutput, as we are not storing it in the parsercache 00205 // key. Force it here. See bug 31445. 00206 $value->setEditSectionTokens( $popts->getEditSection() ); 00207 00208 if ( !$useOutdated && $value->expired( $touched ) ) { 00209 wfIncrStats( "pcache_miss_expired" ); 00210 $cacheTime = $value->getCacheTime(); 00211 wfDebug( "ParserOutput key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" ); 00212 $value = false; 00213 } else { 00214 wfIncrStats( "pcache_hit" ); 00215 } 00216 00217 wfProfileOut( __METHOD__ ); 00218 return $value; 00219 } 00220 00226 public function save( $parserOutput, $article, $popts ) { 00227 $expire = $parserOutput->getCacheExpiry(); 00228 00229 if( $expire > 0 ) { 00230 $now = wfTimestampNow(); 00231 00232 $optionsKey = new CacheTime; 00233 $optionsKey->mUsedOptions = $parserOutput->getUsedOptions(); 00234 $optionsKey->updateCacheExpiry( $expire ); 00235 00236 $optionsKey->setCacheTime( $now ); 00237 $parserOutput->setCacheTime( $now ); 00238 00239 $optionsKey->setContainsOldMagic( $parserOutput->containsOldMagic() ); 00240 00241 $parserOutputKey = $this->getParserOutputKey( $article, 00242 $popts->optionsHash( $optionsKey->mUsedOptions, $article->getTitle() ) ); 00243 00244 // Save the timestamp so that we don't have to load the revision row on view 00245 $parserOutput->setTimestamp( $article->getTimestamp() ); 00246 00247 $parserOutput->mText .= "\n<!-- Saved in parser cache with key $parserOutputKey and timestamp $now -->\n"; 00248 wfDebug( "Saved in parser cache with key $parserOutputKey and timestamp $now\n" ); 00249 00250 // Save the parser output 00251 $this->mMemc->set( $parserOutputKey, $parserOutput, $expire ); 00252 00253 // ...and its pointer 00254 $this->mMemc->set( $this->getOptionsKey( $article ), $optionsKey, $expire ); 00255 } else { 00256 wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" ); 00257 } 00258 } 00259 }