From 2094e578b4ff0fdf6df351c44727b4e23846ac85 Mon Sep 17 00:00:00 2001 From: Jackmcbarn Date: Wed, 28 May 2014 20:54:55 -0400 Subject: [PATCH] Restrict empty-frame cache entries to their parent Remove the parser's global $mTplExpandCache, and replace it with an alternative that is separated by parent frame. This allows the integrity of the empty-frame expansion cache to be maintained while also allowing parent frame access. A page with 3 copies of http://ja.wikipedia.org/wiki/%E4%B8%AD%E5%A4%AE%E7%B7%9A_(%E9%9F%93%E5%9B%BD) has the following statistics: Without this change, there are 4625 cache hits on this page, and a sample of 3 parses took 16.6, 16.9, and 16.8 seconds. With this change, there are 2588 cache hits, and a sample of 3 parses took 16.7, 16.7, and 17.0 seconds. Change-Id: I621e9075e0f136ac188a4d2f53418b7cc957408d --- includes/parser/Parser.php | 10 ++------- includes/parser/Preprocessor.php | 5 +++++ includes/parser/Preprocessor_DOM.php | 32 +++++++++++++++++++++++++++ includes/parser/Preprocessor_Hash.php | 32 +++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 8 deletions(-) diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index d2a20df971..cf174ec3f4 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -167,7 +167,6 @@ class Parser { var $mLinkID; var $mIncludeSizes, $mPPNodeCount, $mGeneratedPPNodeCount, $mHighestExpansionDepth; var $mDefaultSort; - var $mTplExpandCache; # empty-frame expansion cache var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores; var $mExpensiveFunctionCount; # number of expensive parser function calls var $mShowToc, $mForceTocPosition; @@ -321,7 +320,7 @@ class Parser { $this->mStripState = new StripState( $this->mUniqPrefix ); # Clear these on every parse, bug 4549 - $this->mTplExpandCache = $this->mTplRedirCache = $this->mTplDomCache = array(); + $this->mTplRedirCache = $this->mTplDomCache = array(); $this->mShowToc = true; $this->mForceTocPosition = false; @@ -3562,12 +3561,7 @@ class Parser { $text = $newFrame->expand( $text, PPFrame::RECOVER_ORIG ); } elseif ( $titleText !== false && $newFrame->isEmpty() ) { # Expansion is eligible for the empty-frame cache - if ( isset( $this->mTplExpandCache[$titleText] ) ) { - $text = $this->mTplExpandCache[$titleText]; - } else { - $text = $newFrame->expand( $text ); - $this->mTplExpandCache[$titleText] = $text; - } + $text = $newFrame->cachedExpand( $titleText, $text ); } else { # Uncached expansion $text = $newFrame->expand( $text ); diff --git a/includes/parser/Preprocessor.php b/includes/parser/Preprocessor.php index b8e262ab94..25b34fa222 100644 --- a/includes/parser/Preprocessor.php +++ b/includes/parser/Preprocessor.php @@ -94,6 +94,11 @@ interface PPFrame { */ function newChild( $args = false, $title = false, $indexOffset = 0 ); + /** + * Expand a document tree node, caching the result on its parent with the given key + */ + function cachedExpand( $key, $root, $flags = 0 ); + /** * Expand a document tree node */ diff --git a/includes/parser/Preprocessor_DOM.php b/includes/parser/Preprocessor_DOM.php index d15b43ab9c..4f5ebc8041 100644 --- a/includes/parser/Preprocessor_DOM.php +++ b/includes/parser/Preprocessor_DOM.php @@ -983,6 +983,11 @@ class PPFrame_DOM implements PPFrame { */ var $depth; + /** + * @var array + */ + protected $childExpansionCache; + /** * Construct a new preprocessor frame. * @param Preprocessor $preprocessor The parent preprocessor @@ -994,6 +999,7 @@ class PPFrame_DOM implements PPFrame { $this->titleCache = array( $this->title ? $this->title->getPrefixedDBkey() : false ); $this->loopCheckHash = array(); $this->depth = 0; + $this->childExpansionCache = array(); } /** @@ -1043,6 +1049,18 @@ class PPFrame_DOM implements PPFrame { return new PPTemplateFrame_DOM( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title ); } + /** + * @throws MWException + * @param string|int $key + * @param string|PPNode_DOM|DOMDocument $root + * @param int $flags + * @return string + */ + function cachedExpand( $key, $root, $flags = 0 ) { + // we don't have a parent, so we don't have a cache + return $this->expand( $root, $flags ); + } + /** * @throws MWException * @param string|PPNode_DOM|DOMDocument $root @@ -1526,6 +1544,20 @@ class PPTemplateFrame_DOM extends PPFrame_DOM { return $s; } + /** + * @throws MWException + * @param string|int $key + * @param string|PPNode_DOM|DOMDocument $root + * @param int $flags + * @return string + */ + function cachedExpand( $key, $root, $flags = 0 ) { + if ( !isset( $this->parent->childExpansionCache[$key] ) ) { + $this->parent->childExpansionCache[$key] = $this->expand( $root, $flags ); + } + return $this->parent->childExpansionCache[$key]; + } + /** * Returns true if there are no arguments in this frame * diff --git a/includes/parser/Preprocessor_Hash.php b/includes/parser/Preprocessor_Hash.php index a464461165..cb652ac18a 100644 --- a/includes/parser/Preprocessor_Hash.php +++ b/includes/parser/Preprocessor_Hash.php @@ -919,6 +919,11 @@ class PPFrame_Hash implements PPFrame { */ var $depth; + /** + * @var array + */ + protected $childExpansionCache; + /** * Construct a new preprocessor frame. * @param Preprocessor $preprocessor The parent preprocessor @@ -930,6 +935,7 @@ class PPFrame_Hash implements PPFrame { $this->titleCache = array( $this->title ? $this->title->getPrefixedDBkey() : false ); $this->loopCheckHash = array(); $this->depth = 0; + $this->childExpansionCache = array(); } /** @@ -972,6 +978,18 @@ class PPFrame_Hash implements PPFrame { return new PPTemplateFrame_Hash( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title ); } + /** + * @throws MWException + * @param string|int $key + * @param string|PPNode_Hash|DOMDocument $root + * @param int $flags + * @return string + */ + function cachedExpand( $key, $root, $flags = 0 ) { + // we don't have a parent, so we don't have a cache + return $this->expand( $root, $flags ); + } + /** * @throws MWException * @param string|PPNode$root @@ -1426,6 +1444,20 @@ class PPTemplateFrame_Hash extends PPFrame_Hash { return $s; } + /** + * @throws MWException + * @param string|int $key + * @param string|PPNode_Hash|DOMDocument $root + * @param int $flags + * @return string + */ + function cachedExpand( $key, $root, $flags = 0 ) { + if ( !isset( $this->parent->childExpansionCache[$key] ) ) { + $this->parent->childExpansionCache[$key] = $this->expand( $root, $flags ); + } + return $this->parent->childExpansionCache[$key]; + } + /** * Returns true if there are no arguments in this frame * -- 2.20.1