r70783 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r70782‎ | r70783 | r70784 >
Date:21:53, 9 August 2010
Author:platonides
Status:resolved (Comments)
Tags:
Comment:
Use only the page relevant pieces in the parser cache key. Eg. two users with different math options will now
use the same parsercache entry for articles without <math> tags.
The cache key format is kept as a fallback so the old cached entries can be reused.

Should boost parsercache hits, but it also makes easier to pollute the parsercache by tag hooks that behave
badly, directly using $wgUser or $wgLang.

Extensions hooking PageRenderingHash now see !edit=0 and the !printable=1 bits.

Fixes bug 24714 - Usage of {{#dateformat: }} in wikis without $wgUseDynamicDates can lead to unexpected results

Builds upon r70498, r70498, r70501, r70517, r70651, r70653, r70765, r70780.
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/docs/memcached.txt (modified) (history)
  • /trunk/phase3/includes/Article.php (modified) (history)
  • /trunk/phase3/includes/parser/Parser.php (modified) (history)
  • /trunk/phase3/includes/parser/ParserCache.php (modified) (history)
  • /trunk/phase3/includes/parser/ParserOptions.php (modified) (history)

Diff [purge]

Index: trunk/phase3/docs/memcached.txt
@@ -153,17 +153,21 @@
154154 Parser Cache:
155155 stored in: $parserMemc
156156 controlled by: $wgEnableParserCache
157 - key: $wgDBname:pcache:idhash:$pageid-$renderkey!$hash$edit
 157+ key: $wgDBname:pcache:idhash:$pageid-$renderkey!$hash
158158 $pageid: id of the page
159159 $renderkey: 1 if action=render, 0 otherwise
160 - $hash: hash of user options, see User::getPageRenderingHash()
161 - $edit: '!edit=0' if the user can't edit the page, '' otherwise
 160+ $hash: hash of user options applied to the page, see ParserOptions::optionsHash()
162161 ex: wikidb:pcache:idhash:1-0!1!0!!en!2
163162 stores: ParserOutput object
164 - modified by: Article::editUpdates()
165 - expriy: $wgParserCacheExpireTime or one hour if it contains specific magic
166 - words
 163+ modified by: Article::editUpdates() or Article::getOutputFromWikitext()
 164+ expiry: $wgParserCacheExpireTime or less if it contains short lived functions
167165
 166+ key: $wgDBname:pcache:idoptions:$pageid
 167+ stores: CacheTime object with an additional list of used options for the hash,
 168+ serves as ParserCache pointer.
 169+ modified by: ParserCache::save()
 170+ expiry: The same as the ParserCache entry it points to.
 171+
168172 Ping limiter:
169173 controlled by: $wgRateLimits
170174 key: $wgDBname:limiter:action:$action:ip:$ip,
Index: trunk/phase3/includes/Article.php
@@ -996,6 +996,8 @@
997997 case 4:
998998 # Run the parse, protected by a pool counter
999999 wfDebug( __METHOD__ . ": doing uncached parse\n" );
 1000+
 1001+ $this->checkTouched();
10001002 $key = $parserCache->getKey( $this, $parserOptions );
10011003 $poolCounter = PoolCounter::factory( 'Article::view', $key );
10021004 $dirtyCallback = $useParserCache ? array( $this, 'tryDirtyCache' ) : false;
@@ -1493,10 +1495,9 @@
14941496 * @return boolean
14951497 */
14961498 public function tryDirtyCache() {
1497 -
14981499 global $wgOut;
14991500 $parserCache = ParserCache::singleton();
1500 - $options = $this->getParserOptions();
 1501+ $options = clone $this->getParserOptions();
15011502
15021503 if ( $wgOut->isPrintable() ) {
15031504 $options->setIsPrintable( true );
@@ -3609,8 +3610,8 @@
36103611 $edit->revid = $revid;
36113612 $edit->newText = $text;
36123613 $edit->pst = $this->preSaveTransform( $text );
3613 - $options = $this->getParserOptions();
3614 - $edit->output = $wgParser->parse( $edit->pst, $this->mTitle, $options, true, true, $revid );
 3614+ $edit->popts = clone $this->getParserOptions();
 3615+ $edit->output = $wgParser->parse( $edit->pst, $this->mTitle, $edit->popts, true, true, $revid );
36153616 $edit->oldText = $this->getContent();
36163617
36173618 $this->mPreparedEdit = $edit;
@@ -3649,9 +3650,8 @@
36503651
36513652 # Save it to the parser cache
36523653 if ( $wgEnableParserCache ) {
3653 - $popts = $this->getParserOptions();
36543654 $parserCache = ParserCache::singleton();
3655 - $parserCache->save( $editInfo->output, $this, $popts );
 3655+ $parserCache->save( $editInfo->output, $this, $editInfo->popts );
36563656 }
36573657
36583658 # Update the links tables
@@ -4418,7 +4418,7 @@
44194419 global $wgParser, $wgEnableParserCache, $wgUseFileCache;
44204420
44214421 if ( !$parserOptions ) {
4422 - $parserOptions = $this->getParserOptions();
 4422+ $parserOptions = clone $this->getParserOptions();
44234423 }
44244424
44254425 $time = - wfTime();
Index: trunk/phase3/includes/parser/Parser.php
@@ -266,6 +266,7 @@
267267 $this->clearState();
268268 }
269269
 270+ $options->resetUsage();
270271 $this->mOptions = $options;
271272 $this->setTitle( $title ); # Page title has to be set for the pre-processor
272273
@@ -454,6 +455,7 @@
455456 wfProfileIn( __METHOD__ );
456457 $this->clearState();
457458 $this->setOutputType( self::OT_PREPROCESS );
 459+ $options->resetUsage();
458460 $this->mOptions = $options;
459461 $this->setTitle( $title );
460462 if ( $revid !== null ) {
@@ -477,6 +479,7 @@
478480 # Parser (re)initialisation
479481 $this->clearState();
480482 $this->setOutputType( self::OT_PLAIN );
 483+ $options->resetUsage();
481484 $this->mOptions = $options;
482485 $this->setTitle( $title );
483486
@@ -4041,6 +4044,7 @@
40424045 * @return String: the altered wiki markup
40434046 */
40444047 public function preSaveTransform( $text, Title $title, $user, $options, $clearState = true ) {
 4048+ $options->resetUsage();
40454049 $this->mOptions = $options;
40464050 $this->setTitle( $title );
40474051 $this->setOutputType( self::OT_WIKI );
@@ -4265,6 +4269,7 @@
42664270 */
42674271 public function startExternalParse( &$title, $options, $outputType, $clearState = true ) {
42684272 $this->setTitle( $title );
 4273+ $options->resetUsage();
42694274 $this->mOptions = $options;
42704275 $this->setOutputType( $outputType );
42714276 if ( $clearState ) {
@@ -5140,6 +5145,7 @@
51415146 $title = Title::newFromText( $title );
51425147 }
51435148 $this->mTitle = $title;
 5149+ $options->resetUsage();
51445150 $this->mOptions = $options;
51455151 $this->setOutputType( $outputType );
51465152 $text = $this->replaceVariables( $text );
Index: trunk/phase3/includes/parser/ParserCache.php
@@ -31,45 +31,93 @@
3232 }
3333 $this->mMemc = $memCached;
3434 }
35 -
36 - function getKey( $article, $popts ) {
 35+
 36+ protected function getParserOutputKey( $article, $hash ) {
3737 global $wgRequest;
38 -
39 - if( $popts instanceof User ) // It used to be getKey( &$article, &$user )
40 - $popts = ParserOptions::newFromUser( $popts );
41 -
42 - $user = $popts->mUser;
43 - $printable = ( $popts->getIsPrintable() ) ? '!printable=1' : '';
44 - $hash = $user->getPageRenderingHash();
4538
46 - if( ! $popts->getEditSection() ) {
47 - // section edit links have been suppressed
48 - $edit = '!edit=0';
49 - } else {
50 - $edit = '';
51 - }
 39+ // idhash seem to mean 'page id' + 'rendering hash' (r3710)
5240 $pageid = $article->getID();
5341 $renderkey = (int)($wgRequest->getVal('action') == 'render');
54 - $key = wfMemcKey( 'pcache', 'idhash', "{$pageid}-{$renderkey}!{$hash}{$edit}{$printable}" );
 42+
 43+ $key = wfMemcKey( 'pcache', 'idhash', "{$pageid}-{$renderkey}!{$hash}" );
5544 return $key;
5645 }
5746
 47+ protected function getOptionsKey( $article ) {
 48+ $pageid = $article->getID();
 49+ return wfMemcKey( 'pcache', 'idoptions', "{$pageid}" );
 50+ }
 51+
5852 function getETag( $article, $popts ) {
59 - return 'W/"' . $this->getKey($article, $popts) . "--" . $article->mTouched. '"';
 53+ return 'W/"' . $this->getParserOutputKey( $article,
 54+ $popts->optionsHash( ParserOptions::legacyOptions() ) ) .
 55+ "--" . $article->mTouched . '"';
6056 }
6157
62 - function getDirty( $article, $popts ) {
63 - $key = $this->getKey( $article, $popts );
64 - wfDebug( "Trying parser cache $key\n" );
65 - $value = $this->mMemc->get( $key );
 58+ /**
 59+ * Retrieve the ParserOutput from ParserCache, even if it's outdated.
 60+ */
 61+ public function getDirty( $article, $popts ) {
 62+ $value = $this->mMemc->get( $article, $popts, true );
6663 return is_object( $value ) ? $value : false;
6764 }
6865
69 - function get( $article, $popts ) {
 66+ /**
 67+ * Used to provide a unique id for the PoolCounter.
 68+ * It would be preferable to have this code in get()
 69+ * instead of having Article looking in our internals.
 70+ *
 71+ * Precondition: $article->checkTouched() has been called.
 72+ */
 73+ public function getKey( $article, $popts, $useOutdated = true ) {
7074 global $wgCacheEpoch;
 75+
 76+ // Determine the options which affect this article
 77+ $optionsKey = $this->mMemc->get( $this->getOptionsKey( $article ) );
 78+ if ( $optionsKey !== false ) {
 79+ if ( !$useOutdated && $optionsKey->expired( $article->mTouched ) ) {
 80+ wfIncrStats( "pcache_miss_expired" );
 81+ $cacheTime = $optionsKey->getCacheTime();
 82+ wfDebug( "Parser options key expired, touched {$article->mTouched}, epoch $wgCacheEpoch, cached $cacheTime\n" );
 83+ return false;
 84+ }
 85+
 86+ $usedOptions = $optionsKey->mUsedOptions;
 87+ wfDebug( "Parser cache options found.\n" );
 88+ } else {
 89+ # TODO: Fail here $wgParserCacheExpireTime after deployment unless $useOutdated
 90+
 91+ $usedOptions = ParserOptions::legacyOptions();
 92+ }
 93+
 94+ return $this->getParserOutputKey( $article, $popts->optionsHash( $usedOptions ) );
 95+ }
 96+
 97+ /**
 98+ * Retrieve the ParserOutput from ParserCache.
 99+ * false if not found or outdated.
 100+ */
 101+ public function get( $article, $popts, $useOutdated = false ) {
 102+ global $wgCacheEpoch;
71103 wfProfileIn( __METHOD__ );
72104
73 - $value = $this->getDirty( $article, $popts );
 105+ $canCache = $article->checkTouched();
 106+ if ( !$canCache ) {
 107+ // It's a redirect now
 108+ wfProfileOut( __METHOD__ );
 109+ return false;
 110+ }
 111+
 112+ // Having called checkTouched() ensures this will be loaded
 113+ $touched = $article->mTouched;
 114+
 115+ $parserOutputKey = $this->getKey( $article, $popts, $useOutdated );
 116+ if ( $parserOutputKey === false ) {
 117+ wfProfileOut( __METHOD__ );
 118+ return false;
 119+ }
 120+
 121+ $value = $this->mMemc->get( $parserOutputKey );
74122 if ( !$value ) {
75123 wfDebug( "Parser cache miss.\n" );
76124 wfIncrStats( "pcache_miss_absent" );
@@ -78,18 +126,10 @@
79127 }
80128
81129 wfDebug( "Found.\n" );
82 - # Invalid if article has changed since the cache was made
83 - $canCache = $article->checkTouched();
84 - $cacheTime = $value->getCacheTime();
85 - $touched = $article->mTouched;
86 - if ( !$canCache || $value->expired( $touched ) ) {
87 - if ( !$canCache ) {
88 - wfIncrStats( "pcache_miss_invalid" );
89 - wfDebug( "Invalid cached redirect, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
90 - } else {
91 - wfIncrStats( "pcache_miss_expired" );
92 - wfDebug( "Key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
93 - }
 130+
 131+ if ( !$useOutdated && $value->expired( $touched ) ) {
 132+ wfIncrStats( "pcache_miss_expired" );
 133+ wfDebug( "ParserOutput key expired, touched $touched, epoch $wgCacheEpoch, cached $cacheTime\n" );
94134 $value = false;
95135 } else {
96136 if ( isset( $value->mTimestamp ) ) {
@@ -102,25 +142,37 @@
103143 return $value;
104144 }
105145
106 - function save( $parserOutput, $article, $popts ){
107 - $key = $this->getKey( $article, $popts );
 146+
 147+ public function save( $parserOutput, $article, $popts ) {
108148 $expire = $parserOutput->getCacheExpiry();
109149
110 - if( $expire > 0 ) {
 150+ if( $expire > 0 ) {
111151 $now = wfTimestampNow();
 152+
 153+ $optionsKey = new CacheTime;
 154+ $optionsKey->mUsedOptions = $popts->usedOptions();
 155+ $optionsKey->updateCacheExpiry( $expire );
 156+
 157+ $optionsKey->setCacheTime( $now );
112158 $parserOutput->setCacheTime( $now );
113159
 160+ $optionsKey->setContainsOldMagic( $parserOutput->containsOldMagic() );
 161+
 162+ $parserOutputKey = $this->getParserOutputKey( $article, $popts->optionsHash( $optionsKey->mUsedOptions ) );
 163+
114164 // Save the timestamp so that we don't have to load the revision row on view
115165 $parserOutput->mTimestamp = $article->getTimestamp();
116166
117 - $parserOutput->mText .= "\n<!-- Saved in parser cache with key $key and timestamp $now -->\n";
118 - wfDebug( "Saved in parser cache with key $key and timestamp $now\n" );
 167+ $parserOutput->mText .= "\n<!-- Saved in parser cache with key $parserOutputKey and timestamp $now -->\n";
 168+ wfDebug( "Saved in parser cache with key $parserOutputKey and timestamp $now\n" );
119169
120 - $this->mMemc->set( $key, $parserOutput, $expire );
 170+ // Save the parser output
 171+ $this->mMemc->set( $parserOutputKey, $parserOutput, $expire );
121172
 173+ // ...and its pointer
 174+ $this->mMemc->set( $this->getOptionsKey( $article ), $optionsKey, $expire );
122175 } else {
123176 wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
124177 }
125178 }
126 -
127179 }
Index: trunk/phase3/includes/parser/ParserOptions.php
@@ -38,13 +38,18 @@
3939 var $mIsSectionPreview; # Parsing the page for a "preview" operation on a single section
4040 var $mIsPrintable; # Parsing the printable version of the page
4141
 42+
 43+ protected $accessedOptions;
 44+
4245 function getUseDynamicDates() { return $this->mUseDynamicDates; }
4346 function getInterwikiMagic() { return $this->mInterwikiMagic; }
4447 function getAllowExternalImages() { return $this->mAllowExternalImages; }
4548 function getAllowExternalImagesFrom() { return $this->mAllowExternalImagesFrom; }
4649 function getEnableImageWhitelist() { return $this->mEnableImageWhitelist; }
47 - function getEditSection() { return $this->mEditSection; }
48 - function getNumberHeadings() { return $this->mNumberHeadings; }
 50+ function getEditSection() { $this->accessedOptions['editsection'] = true;
 51+ return $this->mEditSection; }
 52+ function getNumberHeadings() { $this->accessedOptions['numberheadings'] = true;
 53+ return $this->mNumberHeadings; }
4954 function getAllowSpecialInclusion() { return $this->mAllowSpecialInclusion; }
5055 function getTidy() { return $this->mTidy; }
5156 function getInterfaceMessage() { return $this->mInterfaceMessage; }
@@ -58,12 +63,15 @@
5964 function getEnableLimitReport() { return $this->mEnableLimitReport; }
6065 function getCleanSignatures() { return $this->mCleanSignatures; }
6166 function getExternalLinkTarget() { return $this->mExternalLinkTarget; }
62 - function getMath() { return $this->mMath; }
63 - function getThumbSize() { return $this->mThumbSize; }
 67+ function getMath() { $this->accessedOptions['math'] = true;
 68+ return $this->mMath; }
 69+ function getThumbSize() { $this->accessedOptions['thumbsize'] = true;
 70+ return $this->mThumbSize; }
6471
6572 function getIsPreview() { return $this->mIsPreview; }
6673 function getIsSectionPreview() { return $this->mIsSectionPreview; }
67 - function getIsPrintable() { return $this->mIsPrintable; }
 74+ function getIsPrintable() { $this->accessedOptions['printable'] = true;
 75+ return $this->mIsPrintable; }
6876
6977 function getSkin() {
7078 if ( !isset( $this->mSkin ) ) {
@@ -73,6 +81,7 @@
7482 }
7583
7684 function getDateFormat() {
 85+ $this->accessedOptions['dateformat'] = true;
7786 if ( !isset( $this->mDateFormat ) ) {
7887 $this->mDateFormat = $this->mUser->getDatePreference();
7988 }
@@ -90,6 +99,7 @@
91100 # Using this fragments the cache and is discouraged. Yes, {{int: }} uses this,
92101 # producing inconsistent tables (Bug 14404).
93102 function getUserLang() {
 103+ $this->accessedOptions['userlang'] = true;
94104 return $this->mUserLang;
95105 }
96106
@@ -191,4 +201,111 @@
192202
193203 wfProfileOut( __METHOD__ );
194204 }
 205+
 206+ /**
 207+ * Returns the options from this ParserOptions which have been used.
 208+ */
 209+ public function usedOptions() {
 210+ return array_keys( $this->accessedOptions );
 211+ }
 212+
 213+ /**
 214+ * Resets the memory of options usage.
 215+ */
 216+ public function resetUsage() {
 217+ $this->accessedOptions = array();
 218+ }
 219+
 220+ /**
 221+ * Returns the full array of options that would have been used by
 222+ * in 1.16.
 223+ * Used to get the old parser cache entries when available.
 224+ */
 225+ public static function legacyOptions() {
 226+ global $wgUseDynamicDates;
 227+ $legacyOpts = array( 'math', 'stubthreshold', 'numberheadings', 'userlang', 'thumbsize', 'editsection', 'printable' );
 228+ if ( $wgUseDynamicDates ) {
 229+ $legacyOpts[] = 'dateformat';
 230+ }
 231+ return $legacyOpts;
 232+ }
 233+
 234+ /**
 235+ * Generate a hash string with the values set on these ParserOptions
 236+ * for the keys given in the array.
 237+ * This will be used as part of the hash key for the parser cache,
 238+ * so users sharign the options with vary for the same page share
 239+ * the same cached data safely.
 240+ *
 241+ * Replaces User::getPageRenderingHash()
 242+ *
 243+ * Extensions which require it should install 'PageRenderingHash' hook,
 244+ * which will give them a chance to modify this key based on their own
 245+ * settings.
 246+ *
 247+ * @since 1.17
 248+ * @return \string Page rendering hash
 249+ */
 250+ public function optionsHash( $forOptions ) {
 251+ global $wgContLang, $wgRenderHashAppend;
 252+
 253+ $confstr = '';
 254+
 255+ if ( in_array( 'math', $forOptions ) )
 256+ $confstr .= $this->mMath;
 257+ else
 258+ $confstr .= '*';
 259+
 260+
 261+ // Space assigned for the stubthreshold but unused
 262+ // since it disables the parser cache, its value will always
 263+ // be 0 when this function is called by parsercache.
 264+ // The conditional is here to avoid a confusing 0
 265+ if ( in_array( 'stubthreshold', $forOptions ) )
 266+ $confstr .= '!0' ;
 267+ else
 268+ $confstr .= '!*' ;
 269+
 270+ if ( in_array( 'dateformat', $forOptions ) )
 271+ $confstr .= '!' . $this->mDateFormat;
 272+
 273+ if ( in_array( 'numberheadings', $forOptions ) )
 274+ $confstr .= '!' . ( $this->mNumberHeadings ? '1' : '' );
 275+ else
 276+ $confstr .= '!*';
 277+
 278+ if ( in_array( 'userlang', $forOptions ) )
 279+ $confstr .= '!' . $this->mUserLang;
 280+ else
 281+ $confstr .= '!*';
 282+
 283+ if ( in_array( 'thumbsize', $forOptions ) )
 284+ $confstr .= '!' . $this->mThumbSize;
 285+ else
 286+ $confstr .= '!*';
 287+
 288+ // add in language specific options, if any
 289+ // FIXME: This is just a way of retrieving the url/user preferred variant
 290+ $confstr .= $wgContLang->getExtraHashOptions();
 291+
 292+ // Since the skin could be overloading link(), it should be
 293+ // included here but in practice, none of our skins do that.
 294+ // $confstr .= "!" . $this->mSkin->getSkinName();
 295+
 296+ $confstr .= $wgRenderHashAppend;
 297+
 298+ if ( !$this->mEditSection && in_array( 'editsection', $forOptions ) )
 299+ $confstr .= '!edit=0';
 300+ if ( $this->mIsPrintable && in_array( 'printable', $forOptions ) )
 301+ $confstr .= '!printable=1';
 302+
 303+ // Give a chance for extensions to modify the hash, if they have
 304+ // extra options or other effects on the parser cache.
 305+ wfRunHooks( 'PageRenderingHash', array( &$confstr ) );
 306+
 307+ // Make it a valid memcached key fragment
 308+ $confstr = str_replace( ' ', '_', $confstr );
 309+
 310+ return $confstr;
 311+ }
195312 }
Index: trunk/phase3/RELEASE-NOTES
@@ -144,6 +144,8 @@
145145 result in a URL ending in "#Hello?" rather than "#Hello.3F".
146146 * (bug 8140) Add dedicated CSS classes to Special:Newpages elements
147147 * (bug 11005) Add CSS class to empty pages in Special:Newpages
 148+* The parser cache is now shared amongst users whose different settings aren't
 149+ used in the page.
148150
149151 === Bug fixes in 1.17 ===
150152 * (bug 17560) Half-broken deletion moved image files to deletion archive
@@ -287,6 +289,8 @@
288290 * (bug 15470) First letters of filenames are always capitalized by upload JS.
289291 * (bug 21215) NoLocalSettings.php doesn't tolerate rewrite rules
290292 * (bug 21052) Fix link color for stubs in NewPages
 293+* (bug 24714) Usage of {{#dateformat: }} in wikis without $wgUseDynamicDates no
 294+ longer pollutes the parser cache.
291295
292296 === API changes in 1.17 ===
293297 * (bug 22738) Allow filtering by action type on query=logevent.

Follow-up revisions

RevisionCommit summaryAuthorDate
r70809Follow up r70783 CR....platonides12:10, 10 August 2010
r70817Follow up r70783. Define variable used in debug message....platonides14:11, 10 August 2010
r70940Followup r70783. Give doEditSectionLink an extra parameter with the language ...platonides12:30, 12 August 2010
r73072Fix getDirty from r70783.platonides16:58, 15 September 2010
r74904Deprecate User::getPageRenderingHash() as follow-up to r70783.platonides17:28, 17 October 2010
r78393Do not access to mTouched internals of Article from a different module per r7...platonides17:49, 14 December 2010
r79018Store the options used by the parsing in ParserOutput, per r70783 CR.platonides19:21, 26 December 2010
r79019Remove ParserOptions clonations, already cloned in getParserOptions()....platonides19:23, 26 December 2010
r79568Partial revert of r79520, follow up to r79558. Unconditionally use the new fo...platonides11:31, 4 January 2011
r79714Prepare for r79568. This uses a different hash key for pages without edit links,...platonides10:51, 6 January 2011
r81741Provisional workaround for parser cache interaction with r70783...brion15:02, 8 February 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r70498Change quickUserCan( 'edit' ) and getIsPrintable() into setEditSection( false )...platonides14:37, 5 August 2010
r70501Move the math option inside ParserOptions instead of having Math.php directly...platonides15:24, 5 August 2010
r70517Make intfunction go accross the ParserOptions....platonides18:43, 5 August 2010
r70651Revert r70533 and the piece of r70501 that it tried to fix. Note and open bug...platonides21:21, 7 August 2010
r70653Make thumbsize option go through ParserOptions....platonides22:35, 7 August 2010
r70765Move pieces related to ParserOutput expiry into a new CacheTime class.platonides14:58, 9 August 2010
r70780Follow up r70653. Missing line.platonides20:39, 9 August 2010

Comments

#Comment by Raymond (talk | contribs)   06:52, 10 August 2010

Seen on translatewiki:

PHP Fatal error: Call to a member function expired() on a non-object in /www/w/includes/parser/ParserCache.php on line 78

#Comment by Platonides (talk | contribs)   12:11, 10 August 2010

It's probably returning null instead of false. Fixed in r70809.

#Comment by Raymond (talk | contribs)   13:47, 10 August 2010

And now on twn:

PHP Notice: Undefined variable: cacheTime in /www/w/includes/parser/ParserCache.php
PHP Fatal error: Call to undefined method User::optionsHash() in /www/w/includes/parser/ParserCache.php on line 99
#Comment by Catrope (talk | contribs)   11:47, 12 August 2010

but it also makes easier to pollute the parsercache by tag hooks that behave badly, directly using $wgUser or $wgLang.

One of the things using $wgLang this way just happens to be Parser::formatHeadings(), for putting the [edit] links in. On TranslateWiki (which is running this code), edit section links are now shown in the language of the user that last edited/purged the page, not the language of the viewing user.

tl;dr: Removing $wgLang from the parser cache key causes breakage, it should be put back in.

#Comment by Platonides (talk | contribs)   12:31, 12 August 2010

It is Linker::doEditSectionLink(), using $wgLang via wfMsg()

Fixed in r70940. Affected pages will need to be purged (or bump $wgCacheEpoch)

#Comment by Tim Starling (talk | contribs)   05:20, 15 September 2010
+	public function getDirty( $article, $popts ) {
+		$value = $this->mMemc->get( $article, $popts, true );

Causes fatal error. Presumably $this->get() was meant.

#Comment by Platonides (talk | contribs)   16:59, 15 September 2010

Right. I did a mixture of ParserCache::get() and the mMemc->get it used to call.

Fixed in r73072.

#Comment by Nikerabbit (talk | contribs)   09:00, 10 October 2010

Can User::getPageRenderingHash() now be removed or at least changed to state it is no longer used, or is it?

#Comment by Platonides (talk | contribs)   14:18, 10 October 2010

Yes. It should be considered deprecated.

I removed one usage in r74593, but CategoryTree is still using it. I asked in bug 20040 about replacing it.

#Comment by Platonides (talk | contribs)   17:29, 17 October 2010

I changed CategoryTree in r74903 and deprecated it in r74904.

#Comment by Tim Starling (talk | contribs)   11:58, 14 December 2010

The use of ParserOptions as an output object here is unacceptable. ParserOutput is for output, ParserOptions is for input.

I suggest having ParserOptions register cache dependencies via a callback function, which should be false by default, meaning that no callback is called. Parser should set a dependency-tracking callback in $this->mOptions during clearState(), and it should clear the callback at the end of each parser entry point, via a new Parser method Parser::shutdown(). ParserOptions should call the callback with a string indicating which option was accessed. The callback function should register this information with ParserOutput.

This should be reverted temporarily (for the 1.17 release) if you are too busy to fix it.

+					$this->checkTouched();
 					$key = $parserCache->getKey( $this, $parserOptions );

It's poor style to call an accessor function for its initialisation side-effects, and then to access private member variables from another module. ParserCache::getKey() should call Article::getTouched(), that's what it's for.

-		$options = $this->getParserOptions();
+		$options = clone $this->getParserOptions();

This is redundant since r70751. All instances of the clone operator that you added here should be removed.

#Comment by Platonides (talk | contribs)   21:24, 19 December 2010

Currently the ParserOutput is stored as-is in the ParserCache whereas this data would be irrelevant there.

  1. Store the options in the ParserCache. We don't mind about wasting bytes.
  2. Return the key in some other way.
  3. Make the Parser return some backwards compatible object which separates the metadata and the useful output.
  4. Provide a ParserOutput::strip() to unset() the unneeded items before storing in the parsercache.

I am more inclined for 1 or 4. Note that other values are also in the same circunstances. For instance $mTemplates is only used after a real parse, then we check the templatelinks table. And so on.

#Comment by Tim Starling (talk | contribs)   01:59, 21 December 2010

Option 1. There's lots of possibly unnecessary data in ParserOutput already, it doesn't matter if we add a bit more. I think this is more likely to be needed than some of the other things that are in there. If you did want to fix it, I think you would want to do it using __sleep(), not any of those other options.

#Comment by Platonides (talk | contribs)   19:32, 26 December 2010

Done in r79018

r79019 deals with the clonations.

#Comment by Happy-melon (talk | contribs)   19:12, 20 December 2010

Does this need to be backed out of 1.17, or can it be properly fixed up in time?

#Comment by Platonides (talk | contribs)   20:25, 20 December 2010

I do plan to fix it. Waiting for Tim reply.

Status & tagging log