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 get( &$article, $popts ) {
00055 global $wgCacheEpoch;
00056 $fname = 'ParserCache::get';
00057 wfProfileIn( $fname );
00058
00059 $key = $this->getKey( $article, $popts );
00060
00061 wfDebug( "Trying parser cache $key\n" );
00062 $value = $this->mMemc->get( $key );
00063 if ( is_object( $value ) ) {
00064 wfDebug( "Found.\n" );
00065 # Delete if article has changed since the cache was made
00066 $canCache = $article->checkTouched();
00067 $cacheTime = $value->getCacheTime();
00068 $touched = $article->mTouched;
00069 if ( !$canCache || $value->expired( $touched ) ) {
00070 if ( !$canCache ) {
00071 wfIncrStats( "pcache_miss_invalid" );
00072 wfDebug( "Invalid cached redirect, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
00073 } else {
00074 wfIncrStats( "pcache_miss_expired" );
00075 wfDebug( "Key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
00076 }
00077 $this->mMemc->delete( $key );
00078 $value = false;
00079 } else {
00080 if ( isset( $value->mTimestamp ) ) {
00081 $article->mTimestamp = $value->mTimestamp;
00082 }
00083 wfIncrStats( "pcache_hit" );
00084 }
00085 } else {
00086 wfDebug( "Parser cache miss.\n" );
00087 wfIncrStats( "pcache_miss_absent" );
00088 $value = false;
00089 }
00090
00091 wfProfileOut( $fname );
00092 return $value;
00093 }
00094
00095 function save( $parserOutput, &$article, $popts ){
00096 global $wgParserCacheExpireTime;
00097 $key = $this->getKey( $article, $popts );
00098
00099 if( $parserOutput->getCacheTime() != -1 ) {
00100
00101 $now = wfTimestampNow();
00102 $parserOutput->setCacheTime( $now );
00103
00104
00105 $parserOutput->mTimestamp = $article->getTimestamp();
00106
00107 $parserOutput->mText .= "\n<!-- Saved in parser cache with key $key and timestamp $now -->\n";
00108 wfDebug( "Saved in parser cache with key $key and timestamp $now\n" );
00109
00110 if( $parserOutput->containsOldMagic() ){
00111 $expire = 3600; # 1 hour
00112 } else {
00113 $expire = $wgParserCacheExpireTime;
00114 }
00115 $this->mMemc->set( $key, $parserOutput, $expire );
00116
00117 } else {
00118 wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
00119 }
00120 }
00121
00122 }