From d509361e676158465acf3c6a8987fe4cc2f1c169 Mon Sep 17 00:00:00 2001 From: daniel Date: Fri, 9 Jan 2015 15:51:15 +0000 Subject: [PATCH] Skip ApiStashEdit if custom DataUpdates are present. Bug: T86305 Change-Id: I423ba39a46a08edf2862b8439169ff91338fb6eb --- includes/api/ApiStashEdit.php | 9 ++++++++- includes/parser/ParserOutput.php | 16 +++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/includes/api/ApiStashEdit.php b/includes/api/ApiStashEdit.php index 938f6c0f06..4d181d61a4 100644 --- a/includes/api/ApiStashEdit.php +++ b/includes/api/ApiStashEdit.php @@ -333,7 +333,14 @@ class ApiStashEdit extends ApiBase { // If an item is renewed, mind the cache TTL determined by config and parser functions $since = time() - wfTimestamp( TS_UNIX, $parserOutput->getTimestamp() ); $ttl = min( $parserOutput->getCacheExpiry() - $since, 5 * 60 ); - if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) ) { + + // Note: ParserOutput with that contains secondary data update callbacks can not be + // stashed, since the callbacks are not serializable (see ParserOtput::__sleep). + // The first data update returned by getSecondaryDataUpdates() is always a LinksUpdate + // instance generated on the fly, so it can be ignored in this context. + $hasCustomDataUpdates = count( $parserOutput->getSecondaryDataUpdates() ) > 1; + + if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) && !$hasCustomDataUpdates ) { // Only store what is actually needed $stashInfo = (object)array( 'pstContent' => $pstContent, diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php index 83f0f69ad8..f155312a85 100644 --- a/includes/parser/ParserOutput.php +++ b/includes/parser/ParserOutput.php @@ -53,7 +53,7 @@ class ParserOutput extends CacheTime { $mTOCEnabled = true; # Whether TOC should be shown, can't override __NOTOC__ private $mIndexPolicy = ''; # 'index' or 'noindex'? Any other value will result in no change. private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys) - private $mSecondaryDataUpdates = array(); # List of DataUpdate, used to save info from the page somewhere else. + private $mSecondaryDataUpdates = null; # List of DataUpdate, used to save info from the page somewhere else. private $mExtensionData = array(); # extra data used by extensions private $mLimitReportData = array(); # Parser limit report data private $mParseStartTime = array(); # Timestamps for getTimeSinceStart() @@ -70,6 +70,8 @@ class ParserOutput extends CacheTime { $this->mCategories = $categoryLinks; $this->mContainsOldMagic = $containsOldMagic; $this->mTitleText = $titletext; + + $this->mSecondaryDataUpdates = array(); } public function getText() { @@ -702,6 +704,9 @@ class ParserOutput extends CacheTime { * be created based on $this->getTitleText() * @param bool $recursive Queue jobs for recursive updates? * + * @throws MWException if called on a ParserOutput instance that was restored from serialization. + * DataUpdates are generally not serializable, so after serialization, they are undefined. + * * @return array An array of instances of DataUpdate */ public function getSecondaryDataUpdates( Title $title = null, $recursive = true ) { @@ -709,6 +714,15 @@ class ParserOutput extends CacheTime { $title = Title::newFromText( $this->getTitleText() ); } + if ( $this->mSecondaryDataUpdates === null ) { + //NOTE: This happens when mSecondaryDataUpdates are lost during serialization + // (see __sleep below). After (un)serialization, getSecondaryDataUpdates() + // has no defined behavior, and should throw an exception. + throw new MWException( 'getSecondaryDataUpdates() must not be called on ParserOutput restored from serialization.' ); + } + + // NOTE: ApiStashEdit knows about this "magic" update object. If this goes away, + // ApiStashEdit::buildStashValue needs to be adjusted. $linksUpdate = new LinksUpdate( $title, $this, $recursive ); return array_merge( $this->mSecondaryDataUpdates, array( $linksUpdate ) ); -- 2.20.1