https://www.mediawiki.org/wiki/Special:Code/MediaWiki/103502

Revision: 103502
Author:   ialex
Date:     2011-11-17 20:21:54 +0000 (Thu, 17 Nov 2011)
Log Message:
-----------
* Added WikiPage::getParserOutput() and changed Article::getParserOutput() to 
use it
* WikiPage::getParserOutput() requires a ParserOptions object (and optionally 
the revision ID) instead of an User object, removes an hidden dependency on 
$wgLang. For this reason, WikiPage::isParserCacheUsed() now also uses a 
ParserOptions object instead of an User object (doesn't change anything in the 
code except the variable name and it's not called in extensions)
* Moved PoolWorkArticleView to WikiPage.php and added an entry in the 
AutoLoader and moved output-related stuff directly in Article::view() so that 
in can be shared with WikiPage::getParserOutput() (removes code duplication, 
etc.)
* Added the revision ID to the PoolCounter key so that it knows which revision 
is being parsed and doesn't wait for another parse operation with same options 
but different revisions
* Removed Article::doViewParse(), Article::tryDirtyCache() and 
Article::getOutputFromWikitext() since they are now integrated in 
PoolWorkArticleView and Article::view() and there are no callers in extensions. 
This also fixes a bug since Article::doViewParse() will get another 
ParserOptions instance with special options set in Article::view() not be 
repercuted.
* Updated DifferenceEngine to use the new system
* Updated docs/memcached.txt to correct method names

Modified Paths:
--------------
    trunk/phase3/docs/memcached.txt
    trunk/phase3/includes/Article.php
    trunk/phase3/includes/AutoLoader.php
    trunk/phase3/includes/WikiPage.php
    trunk/phase3/includes/diff/DifferenceEngine.php

Modified: trunk/phase3/docs/memcached.txt
===================================================================
--- trunk/phase3/docs/memcached.txt     2011-11-17 20:17:19 UTC (rev 103501)
+++ trunk/phase3/docs/memcached.txt     2011-11-17 20:21:54 UTC (rev 103502)
@@ -159,7 +159,7 @@
                $hash: hash of user options applied to the page, see 
ParserOptions::optionsHash()
        ex: wikidb:pcache:idhash:1-0!1!0!!en!2
        stores: ParserOutput object
-       modified by: Article::editUpdates() or Article::getOutputFromWikitext()
+       modified by: WikiPage::doEditUpdates() or PoolWorkArticleView::doWork()
        expiry: $wgParserCacheExpireTime or less if it contains short lived 
functions
 
        key: $wgDBname:pcache:idoptions:$pageid

Modified: trunk/phase3/includes/Article.php
===================================================================
--- trunk/phase3/includes/Article.php   2011-11-17 20:17:19 UTC (rev 103501)
+++ trunk/phase3/includes/Article.php   2011-11-17 20:21:54 UTC (rev 103502)
@@ -453,7 +453,7 @@
                }
 
                # Should the parser cache be used?
-               $useParserCache = $this->mPage->isParserCacheUsed( $wgUser, 
$oldid );
+               $useParserCache = $this->mPage->isParserCacheUsed( 
$parserOptions, $oldid );
                wfDebug( 'Article::view using parser cache: ' . ( 
$useParserCache ? 'yes' : 'no' ) . "\n" );
                if ( $wgUser->getStubThreshold() ) {
                        wfIncrStats( 'pcache_miss_stub' );
@@ -550,16 +550,34 @@
                                        # Run the parse, protected by a pool 
counter
                                        wfDebug( __METHOD__ . ": doing uncached 
parse\n" );
 
-                                       $key = $parserCache->getKey( $this, 
$parserOptions );
-                                       $poolArticleView = new 
PoolWorkArticleView( $this, $key, $useParserCache, $parserOptions );
+                                       $poolArticleView = new 
PoolWorkArticleView( $this, $parserOptions,
+                                               $this->getRevIdFetched(), 
$useParserCache, $this->getContent() );
 
                                        if ( !$poolArticleView->execute() ) {
+                                               $error = 
$poolArticleView->getError();
+                                               if ( $error ) {
+                                                       $wgOut->clearHTML(); // 
for release() errors
+                                                       
$wgOut->enableClientCache( false );
+                                                       $wgOut->setRobotPolicy( 
'noindex,nofollow' );
+
+                                                       $errortext = 
$error->getWikiText( false, 'view-pool-error' );
+                                                       $wgOut->addWikiText( 
'<div class="errorbox">' . $errortext . '</div>' );
+                                               }
                                                # Connection or timeout error
                                                wfProfileOut( __METHOD__ );
                                                return;
-                                       } else {
-                                               $outputDone = true;
                                        }
+
+                                       $this->mParserOutput = 
$poolArticleView->getParserOutput();
+                                       $wgOut->addParserOutput( 
$this->mParserOutput );
+
+                                       # Don't cache a dirty ParserOutput 
object
+                                       if ( $poolArticleView->getIsDirty() ) {
+                                               $wgOut->setSquidMaxage( 0 );
+                                               $wgOut->addHTML( "<!-- parser 
cache is expired, sending anyway due to pool overload-->\n" );
+                                       }
+
+                                       $outputDone = true;
                                        break;
                                # Should be unreachable, but just in case...
                                default:
@@ -1150,67 +1168,6 @@
        }
 
        /**
-        * Execute the uncached parse for action=view
-        * @return bool
-        */
-       public function doViewParse() {
-               global $wgOut;
-
-               $oldid = $this->getOldID();
-               $parserOptions = $this->getParserOptions();
-
-               # Render printable version, use printable version cache
-               $parserOptions->setIsPrintable( $wgOut->isPrintable() );
-
-               # Don't show section-edit links on old revisions... this way 
lies madness.
-               if ( !$this->isCurrent() || $wgOut->isPrintable() || 
!$this->getTitle()->quickUserCan( 'edit' ) ) {
-                       $parserOptions->setEditSection( false );
-               }
-
-               $useParserCache = $this->useParserCache( $oldid );
-               $this->outputWikiText( $this->getContent(), $useParserCache, 
$parserOptions );
-
-               return true;
-       }
-
-       /**
-        * Try to fetch an expired entry from the parser cache. If it is 
present,
-        * output it and return true. If it is not present, output nothing and
-        * return false. This is used as a callback function for
-        * PoolCounter::executeProtected().
-        *
-        * @return boolean
-        */
-       public function tryDirtyCache() {
-               global $wgOut;
-               $parserCache = ParserCache::singleton();
-               $options = $this->getParserOptions();
-
-               if ( $wgOut->isPrintable() ) {
-                       $options->setIsPrintable( true );
-                       $options->setEditSection( false );
-               }
-
-               $output = $parserCache->getDirty( $this, $options );
-
-               if ( $output ) {
-                       wfDebug( __METHOD__ . ": sending dirty output\n" );
-                       wfDebugLog( 'dirty', "dirty output " . 
$parserCache->getKey( $this, $options ) . "\n" );
-                       $wgOut->setSquidMaxage( 0 );
-                       $this->mParserOutput = $output;
-                       $wgOut->addParserOutput( $output );
-                       $wgOut->addHTML( "<!-- parser cache is expired, sending 
anyway due to pool overload-->\n" );
-
-                       return true;
-               } else {
-                       wfDebugLog( 'dirty', "dirty missing\n" );
-                       wfDebug( __METHOD__ . ": no dirty cache\n" );
-
-                       return false;
-               }
-       }
-
-       /**
         * View redirect
         *
         * @param $target Title|Array of destination(s) to redirect
@@ -1642,25 +1599,6 @@
        /**#@-*/
 
        /**
-        * Add the primary page-view wikitext to the output buffer
-        * Saves the text into the parser cache if possible.
-        * Updates templatelinks if it is out of date.
-        *
-        * @param $text String
-        * @param $cache Boolean
-        * @param $parserOptions mixed ParserOptions object, or boolean false
-        */
-       public function outputWikiText( $text, $cache = true, $parserOptions = 
false ) {
-               global $wgOut;
-
-               $this->mParserOutput = $this->getOutputFromWikitext( $text, 
$cache, $parserOptions );
-
-               $this->doCascadeProtectionUpdates( $this->mParserOutput );
-
-               $wgOut->addParserOutput( $this->mParserOutput );
-       }
-
-       /**
         * Lightweight method to get the parser output for a page, checking the 
parser cache
         * and so on. Doesn't consider most of the stuff that WikiPage::view is 
forced to
         * consider, so it's not appropriate to use there.
@@ -1672,96 +1610,15 @@
         * @return ParserOutput or false if the given revsion ID is not found
         */
        public function getParserOutput( $oldid = null, User $user = null ) {
-               global $wgEnableParserCache, $wgUser;
+               global $wgUser;
+
                $user = is_null( $user ) ? $wgUser : $user;
+               $parserOptions = $this->mPage->makeParserOptions( $user );
 
-               wfProfileIn( __METHOD__ );
-               // Should the parser cache be used?
-               $useParserCache = $wgEnableParserCache &&
-                       $user->getStubThreshold() == 0 &&
-                       $this->mPage->exists() &&
-                       $oldid === null;
-
-               wfDebug( __METHOD__ . ': using parser cache: ' . ( 
$useParserCache ? 'yes' : 'no' ) . "\n" );
-
-               if ( $user->getStubThreshold() ) {
-                       wfIncrStats( 'pcache_miss_stub' );
-               }
-
-               if ( $useParserCache ) {
-                       $options = $this->mPage->makeParserOptions( $user );
-                       $parserOutput = ParserCache::singleton()->get( $this, 
$options );
-                       if ( $parserOutput !== false ) {
-                               wfProfileOut( __METHOD__ );
-                               return $parserOutput;
-                       }
-               }
-
-               // Cache miss; parse and output it.
-               if ( $oldid === null ) {
-                       $text = $this->mPage->getRawText();
-               } else {
-                       $rev = Revision::newFromTitle( $this->getTitle(), 
$oldid );
-                       if ( $rev === null ) {
-                               wfProfileOut( __METHOD__ );
-                               return false;
-                       }
-                       $text = $rev->getText();
-               }
-
-               $output = $this->getOutputFromWikitext( $text, $useParserCache 
);
-               wfProfileOut( __METHOD__ );
-               return $output;
+               return $this->mPage->getParserOutput( $parserOptions, $oldid );
        }
 
        /**
-        * This does all the heavy lifting for outputWikitext, except it 
returns the parser
-        * output instead of sending it straight to $wgOut. Makes things nice 
and simple for,
-        * say, embedding thread pages within a discussion system 
(LiquidThreads)
-        *
-        * @param $text string
-        * @param $cache boolean
-        * @param $parserOptions parsing options, defaults to false
-        * @return ParserOutput
-        */
-       public function getOutputFromWikitext( $text, $cache = true, 
$parserOptions = false ) {
-               global $wgParser, $wgEnableParserCache, $wgUseFileCache;
-
-               if ( !$parserOptions ) {
-                       $parserOptions = $this->getParserOptions();
-               }
-
-               $time = - wfTime();
-               $this->mParserOutput = $wgParser->parse( $text, 
$this->getTitle(),
-                       $parserOptions, true, true, $this->getRevIdFetched() );
-               $time += wfTime();
-
-               # Timing hack
-               if ( $time > 3 ) {
-                       wfDebugLog( 'slow-parse', sprintf( "%-5.2f %s", $time,
-                               $this->getTitle()->getPrefixedDBkey() ) );
-               }
-
-               if ( $wgEnableParserCache && $cache && 
$this->mParserOutput->isCacheable() ) {
-                       $parserCache = ParserCache::singleton();
-                       $parserCache->save( $this->mParserOutput, $this, 
$parserOptions );
-               }
-
-               // Make sure file cache is not used on uncacheable content.
-               // Output that has magic words in it can still use the parser 
cache
-               // (if enabled), though it will generally expire sooner.
-               if ( !$this->mParserOutput->isCacheable() || 
$this->mParserOutput->containsOldMagic() ) {
-                       $wgUseFileCache = false;
-               }
-
-               if ( $this->isCurrent() ) {
-                       $this->mPage->doCascadeProtectionUpdates( 
$this->mParserOutput );
-               }
-
-               return $this->mParserOutput;
-       }
-
-       /**
         * Get parser options suitable for rendering the primary article 
wikitext
         * @return ParserOptions|false
         */
@@ -2063,68 +1920,3 @@
        }
        // ******
 }
-
-class PoolWorkArticleView extends PoolCounterWork {
-
-       /**
-        * @var Article
-        */
-       private $mArticle;
-
-       function __construct( $article, $key, $useParserCache, $parserOptions ) 
{
-               parent::__construct( 'ArticleView', $key );
-               $this->mArticle = $article;
-               $this->cacheable = $useParserCache;
-               $this->parserOptions = $parserOptions;
-       }
-
-       /**
-        * @return bool
-        */
-       function doWork() {
-               return $this->mArticle->doViewParse();
-       }
-
-       /**
-        * @return bool
-        */
-       function getCachedWork() {
-               global $wgOut;
-
-               $parserCache = ParserCache::singleton();
-               $this->mArticle->mParserOutput = $parserCache->get( 
$this->mArticle, $this->parserOptions );
-
-               if ( $this->mArticle->mParserOutput !== false ) {
-                       wfDebug( __METHOD__ . ": showing contents parsed by 
someone else\n" );
-                       $wgOut->addParserOutput( $this->mArticle->mParserOutput 
);
-                       # Ensure that UI elements requiring revision ID have
-                       # the correct version information.
-                       $wgOut->setRevisionId( $this->mArticle->getLatest() );
-                       return true;
-               }
-               return false;
-       }
-
-       /**
-        * @return bool
-        */
-       function fallback() {
-               return $this->mArticle->tryDirtyCache();
-       }
-
-       /**
-        * @param $status Status
-        */
-       function error( $status ) {
-               global $wgOut;
-
-               $wgOut->clearHTML(); // for release() errors
-               $wgOut->enableClientCache( false );
-               $wgOut->setRobotPolicy( 'noindex,nofollow' );
-
-               $errortext = $status->getWikiText( false, 'view-pool-error' );
-               $wgOut->addWikiText( '<div class="errorbox">' . $errortext . 
'</div>' );
-
-               return false;
-       }
-}

Modified: trunk/phase3/includes/AutoLoader.php
===================================================================
--- trunk/phase3/includes/AutoLoader.php        2011-11-17 20:17:19 UTC (rev 
103501)
+++ trunk/phase3/includes/AutoLoader.php        2011-11-17 20:21:54 UTC (rev 
103502)
@@ -168,6 +168,7 @@
        'PoolCounter' => 'includes/PoolCounter.php',
        'PoolCounter_Stub' => 'includes/PoolCounter.php',
        'PoolCounterWork' => 'includes/PoolCounter.php',
+       'PoolWorkArticleView' => 'includes/WikiPage.php',
        'Preferences' => 'includes/Preferences.php',
        'PreferencesForm' => 'includes/Preferences.php',
        'PrefixSearch' => 'includes/PrefixSearch.php',

Modified: trunk/phase3/includes/WikiPage.php
===================================================================
--- trunk/phase3/includes/WikiPage.php  2011-11-17 20:17:19 UTC (rev 103501)
+++ trunk/phase3/includes/WikiPage.php  2011-11-17 20:21:54 UTC (rev 103502)
@@ -708,21 +708,62 @@
        /**
         * Should the parser cache be used?
         *
-        * @param $user User The relevant user
+        * @param $parserOptions ParserOptions to check
         * @param $oldid int
         * @return boolean
         */
-       public function isParserCacheUsed( User $user, $oldid ) {
+       public function isParserCacheUsed( ParserOptions $parserOptions, $oldid 
) {
                global $wgEnableParserCache;
 
                return $wgEnableParserCache
-                       && $user->getStubThreshold() == 0
+                       && $parserOptions->getStubThreshold() == 0
                        && $this->exists()
                        && ( $oldid === null || $oldid === 0 || $oldid === 
$this->getLatest() )
                        && $this->mTitle->isWikitextPage();
        }
 
        /**
+        * Get a ParserOutput for the given ParserOptions and revision ID.
+        * The the parser cache will be used if possible.
+        *
+        * @since 1.19
+        * @param $parserOptions ParserOptions to use for the parse operation
+        * @param $oldid Revision ID to get the text from, passing null or 0 
will
+        *               get the current revision (default value)
+        * @return ParserOutput or false if the revision was not found
+        */
+       public function getParserOutput( ParserOptions $parserOptions, $oldid = 
null ) {
+               global $wgParser;
+
+               wfProfileIn( __METHOD__ );
+
+               $useParserCache = $this->isParserCacheUsed( $parserOptions, 
$oldid );
+               wfDebug( __METHOD__ . ': using parser cache: ' . ( 
$useParserCache ? 'yes' : 'no' ) . "\n" );
+               if ( $parserOptions->getStubThreshold() ) {
+                       wfIncrStats( 'pcache_miss_stub' );
+               }
+
+               if ( $useParserCache ) {
+                       $parserOutput = ParserCache::singleton()->get( $this, 
$parserOptions );
+                       if ( $parserOutput !== false ) {
+                               wfProfileOut( __METHOD__ );
+                               return $parserOutput;
+                       }
+               }
+
+               if ( $oldid === null || $oldid === 0 ) {
+                       $oldid = $this->getLatest();
+               }
+
+               $pool = new PoolWorkArticleView( $this, $parserOptions, $oldid, 
$useParserCache );
+               $pool->execute();
+
+               wfProfileOut( __METHOD__ );
+
+               return $pool->getParserOutput();
+       }
+
+       /**
         * Perform the actions of a page purging
         */
        public function doPurge() {
@@ -2671,6 +2712,183 @@
         */
        public function useParserCache( $oldid ) {
                global $wgUser;
-               return $this->isParserCacheUsed( $wgUser, $oldid );
+               return $this->isParserCacheUsed( ParserOptions::newFromUser( 
$wgUser ), $oldid );
        }
 }
+
+class PoolWorkArticleView extends PoolCounterWork {
+
+       /**
+        * @var Page
+        */
+       private $page;
+
+       /**
+        * @var string
+        */
+       private $cacheKey;
+
+       /**
+        * @var integer
+        */
+       private $revid;
+
+       /**
+        * @var ParserOptions
+        */
+       private $parserOptions;
+
+       /**
+        * @var string|null
+        */
+       private $text;
+
+       /**
+        * @var ParserOutput|false
+        */
+       private $parserOutput = false;
+
+       /**
+        * @var bool
+        */
+       private $isDirty = false;
+
+       /**
+        * @var Status|false
+        */
+       private $error = false;
+
+       /**
+        * Constructor
+        *
+        * @param $page Page
+        * @param $revid Integer: ID of the revision being parsed
+        * @param $useParserCache Boolean: whether to use the parser cache
+        * @param $parserOptions parserOptions to use for the parse operation
+        * @param $text String: text to parse or null to load it
+        */
+       function __construct( Page $page, ParserOptions $parserOptions, $revid, 
$useParserCache, $text = null ) {
+               $this->page = $page;
+               $this->revid = $revid;
+               $this->cacheable = $useParserCache;
+               $this->parserOptions = $parserOptions;
+               $this->text = $text;
+               $this->cacheKey = ParserCache::singleton()->getKey( $page, 
$parserOptions );
+               parent::__construct( 'ArticleView', $this->cacheKey . ':revid:' 
. $revid );
+       }
+
+       /**
+        * Get the ParserOutput from this object, or false in case of failure
+        *
+        * @return ParserOutput
+        */
+       public function getParserOutput() {
+               return $this->parserOutput;
+       }
+
+       /**
+        * Get whether the ParserOutput is a dirty one (i.e. expired)
+        *
+        * @return bool
+        */
+       public function getIsDirty() {
+               return $this->isDirty();
+       }
+
+       /**
+        * Get a Status object in case of error or false otherwise
+        *
+        * @return Status|false
+        */
+       public function getError() {
+               return $this->error;
+       }
+
+       /**
+        * @return bool
+        */
+       function doWork() {
+               global $wgParser, $wgUseFileCache;
+
+               $isCurrent = $this->revid === $this->page->getLatest();
+
+               if ( $this->text !== null ) {
+                       $text = $this->text;
+               } elseif ( $isCurrent ) {
+                       $text = $this->page->getRawText();
+               } else {
+                       $rev = Revision::newFromTitle( $this->page->getTitle(), 
$this->revid );
+                       if ( $rev === null ) {
+                               return false;
+                       }
+                       $text = $rev->getText();
+               }
+
+               $time = - wfTime();
+               $this->parserOutput = $wgParser->parse( $text, 
$this->page->getTitle(),
+                       $this->parserOptions, true, true, $this->revid );
+               $time += wfTime();
+
+               # Timing hack
+               if ( $time > 3 ) {
+                       wfDebugLog( 'slow-parse', sprintf( "%-5.2f %s", $time,
+                               $this->page->getTitle()->getPrefixedDBkey() ) );
+               }
+
+               if ( $this->cacheable && $this->parserOutput->isCacheable() ) {
+                       ParserCache::singleton()->save( $this->parserOutput, 
$this->page, $this->parserOptions );
+               }
+
+               // Make sure file cache is not used on uncacheable content.
+               // Output that has magic words in it can still use the parser 
cache
+               // (if enabled), though it will generally expire sooner.
+               if ( !$this->parserOutput->isCacheable() || 
$this->parserOutput->containsOldMagic() ) {
+                       $wgUseFileCache = false;
+               }
+
+               if ( $isCurrent ) {
+                       $this->page->doCascadeProtectionUpdates( 
$this->parserOutput );
+               }
+       }
+
+       /**
+        * @return bool
+        */
+       function getCachedWork() {
+               $this->parserOutput = ParserCache::singleton()->get( 
$this->page, $this->parserOptions );
+
+               if ( $this->parserOutput === false ) {
+                       wfDebug( __METHOD__ . ": parser cache miss\n" );
+                       return false;
+               } else {
+                       wfDebug( __METHOD__ . ": parser cache hit\n" );
+                       return true;
+               }
+       }
+
+       /**
+        * @return bool
+        */
+       function fallback() {
+               $this->parserOutput = ParserCache::singleton()->getDirty( 
$this->page, $this->parserOptions );
+
+               if ( $this->parserOutput === false ) {
+                       wfDebugLog( 'dirty', "dirty missing\n" );
+                       wfDebug( __METHOD__ . ": no dirty cache\n" );
+                       return false;
+               } else {
+                       wfDebug( __METHOD__ . ": sending dirty output\n" );
+                       wfDebugLog( 'dirty', "dirty output {$this->cacheKey}\n" 
);
+                       $this->isDirty = true;
+                       return true;
+               }
+       }
+
+       /**
+        * @param $status Status
+        */
+       function error( $status ) {
+               $this->error = $status;
+               return false;
+       }
+}

Modified: trunk/phase3/includes/diff/DifferenceEngine.php
===================================================================
--- trunk/phase3/includes/diff/DifferenceEngine.php     2011-11-17 20:17:19 UTC 
(rev 103501)
+++ trunk/phase3/includes/diff/DifferenceEngine.php     2011-11-17 20:21:54 UTC 
(rev 103502)
@@ -516,9 +516,8 @@
                        } elseif ( !wfRunHooks( 'ArticleViewCustom', array( 
$this->mNewtext, $this->mNewPage, $out ) ) ) {
                                // Handled by extension
                        } else {
-                               # Use the current version parser cache if 
applicable
+                               // Normal page
                                $wikiPage = WikiPage::factory( $this->mNewPage 
);
-                               $useParserCache = $wikiPage->isParserCacheUsed( 
$this->getUser(), $this->mNewid );
 
                                $parserOptions = ParserOptions::newFromContext( 
$this->getContext() );
                                $parserOptions->enableLimitReport();
@@ -528,15 +527,11 @@
                                        $parserOptions->setEditSection( false );
                                }
 
-                               $parserOutput = false;
-                               if ( $useParserCache ) {
-                                       $parserOutput = 
ParserCache::singleton()->get( $wikiPage, $parserOptions );
-                               }
+                               $parserOutput = $wikiPage->getParserOutput( 
$parserOptions, $this->mNewid );
 
+                               # WikiPage::getParserOutput() should not return 
false, but just in case
                                if( $parserOutput ) {
                                        $out->addParserOutput( $parserOutput );
-                               } else {
-                                       $out->addWikiTextTidy( $this->mNewtext 
);
                                }
                        }
                }


_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to