00001 <?php
00006 class ParserCache {
00010 public static function singleton() {
00011 static $instance;
00012 if ( !isset( $instance ) ) {
00013 global $parserMemc;
00014 $instance = new ParserCache( $parserMemc );
00015 }
00016 return $instance;
00017 }
00018
00025 function __construct( $memCached ) {
00026 $this->mMemc = $memCached;
00027 }
00028
00029 function getKey( $article, $popts ) {
00030 global $wgRequest;
00031
00032 if( $popts instanceof User )
00033 $popts = ParserOptions::newFromUser( $popts );
00034
00035 $user = $popts->mUser;
00036 $printable = ( $popts->getIsPrintable() ) ? '!printable=1' : '';
00037 $hash = $user->getPageRenderingHash();
00038 if( !$article->mTitle->quickUserCan( 'edit' ) ) {
00039
00040 $edit = '!edit=0';
00041 } else {
00042 $edit = '';
00043 }
00044 $pageid = $article->getID();
00045 $renderkey = (int)($wgRequest->getVal('action') == 'render');
00046 $key = wfMemcKey( 'pcache', 'idhash', "{$pageid}-{$renderkey}!{$hash}{$edit}{$printable}" );
00047 return $key;
00048 }
00049
00050 function getETag( $article, $popts ) {
00051 return 'W/"' . $this->getKey($article, $popts) . "--" . $article->mTouched. '"';
00052 }
00053
00054 function getDirty( $article, $popts ) {
00055 $key = $this->getKey( $article, $popts );
00056 wfDebug( "Trying parser cache $key\n" );
00057 $value = $this->mMemc->get( $key );
00058 return is_object( $value ) ? $value : false;
00059 }
00060
00061 function get( $article, $popts ) {
00062 global $wgCacheEpoch;
00063 wfProfileIn( __METHOD__ );
00064
00065 $value = $this->getDirty( $article, $popts );
00066 if ( !$value ) {
00067 wfDebug( "Parser cache miss.\n" );
00068 wfIncrStats( "pcache_miss_absent" );
00069 wfProfileOut( __METHOD__ );
00070 return false;
00071 }
00072
00073 wfDebug( "Found.\n" );
00074 # Invalid if article has changed since the cache was made
00075 $canCache = $article->checkTouched();
00076 $cacheTime = $value->getCacheTime();
00077 $touched = $article->mTouched;
00078 if ( !$canCache || $value->expired( $touched ) ) {
00079 if ( !$canCache ) {
00080 wfIncrStats( "pcache_miss_invalid" );
00081 wfDebug( "Invalid cached redirect, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
00082 } else {
00083 wfIncrStats( "pcache_miss_expired" );
00084 wfDebug( "Key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
00085 }
00086 $value = false;
00087 } else {
00088 if ( isset( $value->mTimestamp ) ) {
00089 $article->mTimestamp = $value->mTimestamp;
00090 }
00091 wfIncrStats( "pcache_hit" );
00092 }
00093
00094 wfProfileOut( __METHOD__ );
00095 return $value;
00096 }
00097
00098 function save( $parserOutput, $article, $popts ){
00099 global $wgParserCacheExpireTime;
00100 $key = $this->getKey( $article, $popts );
00101
00102 if( $parserOutput->getCacheTime() != -1 ) {
00103
00104 $now = wfTimestampNow();
00105 $parserOutput->setCacheTime( $now );
00106
00107
00108 $parserOutput->mTimestamp = $article->getTimestamp();
00109
00110 $parserOutput->mText .= "\n<!-- Saved in parser cache with key $key and timestamp $now -->\n";
00111 wfDebug( "Saved in parser cache with key $key and timestamp $now\n" );
00112
00113 if( $parserOutput->containsOldMagic() ){
00114 $expire = 3600; # 1 hour
00115 } else {
00116 $expire = $wgParserCacheExpireTime;
00117 }
00118 $this->mMemc->set( $key, $parserOutput, $expire );
00119
00120 } else {
00121 wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
00122 }
00123 }
00124
00125 }