Try to output editsection markers instead of rendered editsection links and defer...
authorDaniel Friesen <dantman@users.mediawiki.org>
Mon, 3 Jan 2011 20:17:20 +0000 (20:17 +0000)
committerDaniel Friesen <dantman@users.mediawiki.org>
Mon, 3 Jan 2011 20:17:20 +0000 (20:17 +0000)
Doing this allows skins to override doEditSectionLinks without poluting the parser cache or fragmenting the parser cache more.
As a side effect it eliminates the primary cause of user language based parser cache fragmentation.
Because this makes most old parser cache entries invalid $wgUseEditSectionTokens is provided so that large installations like Wikipedia can keep their old parser cache entries.

RELEASE-NOTES
includes/DefaultSettings.php
includes/parser/Parser.php
includes/parser/ParserOptions.php
includes/parser/ParserOutput.php

index 2e32db2..1ee6a97 100644 (file)
@@ -26,6 +26,11 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * Skin names are no longer created based on a ucfirst version of the key in $wgValidSkinNames but now
   the value. This means for $wgValidSkinNames["monobook"] = "MonoBook"; the skin
   loader will no longer try loading SkinMonobook and will instead load SkinMonoBook.
+* The parser now attempts to output markers for editsection tokens and defer the rendering
+  of them so skin and language specific markup does not need to be saved inside the parser cache
+  note that this changes the cache key making all old entries in the parser cache invalid you
+  can set $wgUseEditSectionTokens to false to disable this and keep your old parser cache entries.
+  Note that this feature should reduce parser cache fragmentation when enabled.
 
 === New features in 1.18 ===
 * Added a special page, disabled by default, that allows users with the
index 48f8aed..02cc4eb 100644 (file)
@@ -2825,6 +2825,18 @@ $wgEnableScaryTranscluding = false;
  */
 $wgTranscludeCacheExpiry = 3600;
 
+/**
+ * Output edit section links as tokens in the parser output for articles instead
+ * of directly as markup.
+ * This feature changes the default parser cache key so it's presented with a
+ * configuration option so that large installations with a large number of already
+ * existing parser cache keys can retain them.
+ * The purpose of this feature is to allow skins to customize the editsection
+ * links, however it has the side effect of also removing the most common use of
+ * the getUserLang parser option which causes cache fragmentation by user lang.
+ */
+$wgUseEditSectionTokens = true;
+
 /** @} */ # end of parser settings }
 
 /************************************************************************//**
index 4a8eadf..b723bea 100644 (file)
@@ -3696,6 +3696,12 @@ class Parser {
                } else {
                        $showEditLink = $this->mOptions->getEditSection();
                }
+               if ( $showEditLink ) {
+                       $editLinkAsToken = $this->mOptions->getEditSectionTokens();
+                       if ( $editLinkAsToken ) {
+                               $this->mOutput->setEditSectionTokens( "{$this->mUniqPrefix}-editsection-", self::MARKER_SUFFIX );
+                       }
+               }
 
                # Get all headlines for numbering them and adding funky stuff like [edit]
                # links - this is for later, but we need the number of headlines right now
@@ -3949,12 +3955,28 @@ class Parser {
 
                        # give headline the correct <h#> tag
                        if ( $showEditLink && $sectionIndex !== false ) {
-                               if ( $isTemplate ) {
-                                       # Put a T flag in the section identifier, to indicate to extractSections()
-                                       # that sections inside <includeonly> should be counted.
-                                       $editlink = $sk->doEditSectionLink( Title::newFromText( $titleText ), "T-$sectionIndex", null, $this->mOptions->getUserLang() );
+                               if ( $editLinkAsToken ) {
+                                       // Output edit section links as markers with styles that can be customized by skins
+                                       if ( $isTemplate ) {
+                                               # Put a T flag in the section identifier, to indicate to extractSections()
+                                               # that sections inside <includeonly> should be counted.
+                                               $editlinkArgs = array( $titleText, "T-$sectionIndex", null );
+                                       } else {
+                                               $editlinkArgs = array( $this->mTitle->getPrefixedText(), $sectionIndex, $headlineHint );
+                                       }
+                                       // We use nearly the same structure as uniqPrefix and the marker stuffix (besides there being nothing random)
+                                       // However the this is output into the parser output itself not replaced early, so we hardcode this in case
+                                       // the constants change in a different version of MediaWiki, which would break this code.
+                                       $editlink = "{$this->mUniqPrefix}-editsection-" . serialize($editlinkArgs) . self::MARKER_SUFFIX;
                                } else {
-                                       $editlink = $sk->doEditSectionLink( $this->mTitle, $sectionIndex, $headlineHint, $this->mOptions->getUserLang() );
+                                       // Output edit section links directly as markup like we used to
+                                       if ( $isTemplate ) {
+                                               # Put a T flag in the section identifier, to indicate to extractSections()
+                                               # that sections inside <includeonly> should be counted.
+                                               $editlink = $sk->doEditSectionLink( Title::newFromText( $titleText ), "T-$sectionIndex", null, $this->mOptions->getUserLang() );
+                                       } else {
+                                               $editlink = $sk->doEditSectionLink( $this->mTitle, $sectionIndex, $headlineHint, $this->mOptions->getUserLang() );
+                                       }
                                }
                        } else {
                                $editlink = '';
index 62a6c7c..52d96d4 100644 (file)
@@ -21,6 +21,7 @@ class ParserOptions {
        var $mSkin = null;               # Reference to the preferred skin
        var $mDateFormat = null;         # Date format index
        var $mEditSection = true;        # Create "edit section" links
+       var $mEditSectionTokens = false; # Output replaceable tokens for editsections instead of markup
        var $mAllowSpecialInclusion;     # Allow inclusion of special pages
        var $mTidy = false;              # Ask for tidy cleanup
        var $mInterfaceMessage = false;  # Which lang to call for PLURAL and GRAMMAR
@@ -58,6 +59,8 @@ class ParserOptions {
        function getEnableImageWhitelist()          { return $this->mEnableImageWhitelist; }
        function getEditSection()                   { $this->optionUsed('editsection');
                                                                                                  return $this->mEditSection; }
+       function getEditSectionTokens()             { $this->optionUsed('editsectiontokens');
+                                                                                                 return $this->mEditSectionTokens; }
        function getNumberHeadings()                { $this->optionUsed('numberheadings');
                                                                                                  return $this->mNumberHeadings; }
        function getAllowSpecialInclusion()         { return $this->mAllowSpecialInclusion; }
@@ -123,6 +126,7 @@ class ParserOptions {
        function setEnableImageWhitelist( $x )      { return wfSetVar( $this->mEnableImageWhitelist, $x ); }
        function setDateFormat( $x )                { return wfSetVar( $this->mDateFormat, $x ); }
        function setEditSection( $x )               { return wfSetVar( $this->mEditSection, $x ); }
+       function setEditSectionTokens( $x )         { return wfSetVar( $this->mEditSectionTokens, $x ); }
        function setNumberHeadings( $x )            { return wfSetVar( $this->mNumberHeadings, $x ); }
        function setAllowSpecialInclusion( $x )     { return wfSetVar( $this->mAllowSpecialInclusion, $x ); }
        function setTidy( $x )                      { return wfSetVar( $this->mTidy, $x); }
@@ -171,7 +175,7 @@ class ParserOptions {
        function initialiseFromUser( $userInput ) {
                global $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages;
                global $wgAllowExternalImagesFrom, $wgEnableImageWhitelist, $wgAllowSpecialInclusion, $wgMaxArticleSize;
-               global $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth, $wgCleanSignatures;
+               global $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth, $wgCleanSignatures, $wgUseEditSectionTokens;
                global $wgExternalLinkTarget, $wgLang;
 
                wfProfileIn( __METHOD__ );
@@ -201,6 +205,7 @@ class ParserOptions {
                $this->mMaxTemplateDepth = $wgMaxTemplateDepth;
                $this->mCleanSignatures = $wgCleanSignatures;
                $this->mExternalLinkTarget = $wgExternalLinkTarget;
+               $this->mEditSectionTokens = $wgUseEditSectionTokens;
 
                $this->mNumberHeadings = $user->getOption( 'numberheadings' );
                $this->mMath = $user->getOption( 'math' );
@@ -307,6 +312,8 @@ class ParserOptions {
 
                if ( !$this->mEditSection && in_array( 'editsection', $forOptions ) )
                        $confstr .= '!edit=0';
+               if ( $this->mEditSectionTokens && in_array( 'editsectiontokens', $forOptions ) )
+                       $confstr .= '!estok=1';
                if (  $this->mIsPrintable && in_array( 'printable', $forOptions ) )
                        $confstr .= '!printable=1';
 
index 6a60a03..59552ad 100644 (file)
@@ -119,6 +119,7 @@ class ParserOutput extends CacheTime {
                $mOutputHooks = array(),      # Hook tags as per $wgParserOutputHooks
                $mWarnings = array(),         # Warning text to be returned to the user. Wikitext formatted, in the key only
                $mSections = array(),         # Table of contents
+               $mEditSectionTokens = false,  # prefix/suffix markers if edit sections were output as tokens
                $mProperties = array(),       # Name/value pairs to be cached in the DB
                $mTOCHTML = '';               # HTML of the TOC
        private $mIndexPolicy = '';           # 'index' or 'noindex'?  Any other value will result in no change.
@@ -134,13 +135,34 @@ class ParserOutput extends CacheTime {
                $this->mTitleText = $titletext;
        }
 
-       function getText()                   { return $this->mText; }
+       function getText() {
+               if ( $this->mEditSectionTokens ) {
+                       $editSectionTokens = $this->mEditSectionTokens;
+                       return preg_replace_callback( "#{$editSectionTokens[0]}(.*?){$editSectionTokens[1]}#", array( &$this, 'replaceEditSectionLinksCallback' ), $this->mText );
+               }
+               return $this->mText;
+       }
+       
+       /**
+        * callback used by getText to replace editsection tokens
+        * @private
+        */
+       function replaceEditSectionLinksCallback( $m ) {
+               global $wgUser, $wgLang;
+               $args = unserialize($m[1]);
+               $args[0] = Title::newFromText( $args[0] );
+               $args[] = $wgLang->getCode();
+               $skin = $wgUser->getSkin();
+               return call_user_func_array( array( $skin, 'doEditSectionLink' ), $args );
+       }
+
        function &getLanguageLinks()         { return $this->mLanguageLinks; }
        function getInterwikiLinks()         { return $this->mInterwikiLinks; }
        function getCategoryLinks()          { return array_keys( $this->mCategories ); }
        function &getCategories()            { return $this->mCategories; }
        function getTitleText()              { return $this->mTitleText; }
        function getSections()               { return $this->mSections; }
+       function getEditSectionTokens()      { return $this->mEditSectionTokens; }
        function &getLinks()                 { return $this->mLinks; }
        function &getTemplates()             { return $this->mTemplates; }
        function &getImages()                { return $this->mImages; }
@@ -159,6 +181,7 @@ class ParserOutput extends CacheTime {
 
        function setTitleText( $t )          { return wfSetVar( $this->mTitleText, $t ); }
        function setSections( $toc )         { return wfSetVar( $this->mSections, $toc ); }
+       function setEditSectionTokens( $p, $s ) { return wfSetVar( $this->mEditSectionTokens, array( $p, $s ) ); }
        function setIndexPolicy( $policy )   { return wfSetVar( $this->mIndexPolicy, $policy ); }
        function setTOCHTML( $tochtml )      { return wfSetVar( $this->mTOCHTML, $tochtml ); }