Aaron Schulz has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/184463

Change subject: Introduced LazyDataUpdate class
......................................................................

Introduced LazyDataUpdate class

* ParserOutput now accepts these objects as updates, and resolves them on
  the fly in the accessor.
* Made the edit stash API cache the parser output only if all the updates
  are serializable or implicit.

Bug: T86305
Change-Id: I9499aaf2e8501a0db8a24e244cacd9a65518a7b2
---
M autoload.php
M includes/api/ApiStashEdit.php
M includes/parser/ParserOutput.php
3 files changed, 53 insertions(+), 20 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/63/184463/1

diff --git a/autoload.php b/autoload.php
index 674d4b0..da48c0f 100644
--- a/autoload.php
+++ b/autoload.php
@@ -637,6 +637,7 @@
        'LanguageZh_hans' => __DIR__ . '/languages/classes/LanguageZh_hans.php',
        'Languages' => __DIR__ . '/maintenance/language/languages.inc',
        'LayeredParameterizedPassword' => __DIR__ . 
'/includes/password/LayeredParameterizedPassword.php',
+       'LazyDataUpdate' => __DIR__ . '/includes/deferred/LazyDataUpdate.php',
        'LegacyLogFormatter' => __DIR__ . '/includes/logging/LogFormatter.php',
        'License' => __DIR__ . '/includes/Licenses.php',
        'Licenses' => __DIR__ . '/includes/Licenses.php',
diff --git a/includes/api/ApiStashEdit.php b/includes/api/ApiStashEdit.php
index 09489e4..44e5490 100644
--- a/includes/api/ApiStashEdit.php
+++ b/includes/api/ApiStashEdit.php
@@ -336,9 +336,9 @@
 
                // Note: ParserOutput with that contains secondary data update 
callbacks can not be
                // stashed, since the callbacks are not serializable (see 
ParserOutput::__sleep).
-               $hasCustomDataUpdates = $parserOutput->hasCustomDataUpdates();
+               $fullySerializable = 
$parserOutput->areSecondaryUpdatesSerializable();
 
-               if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) && 
!$hasCustomDataUpdates ) {
+               if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) && 
$fullySerializable ) {
                        // Only store what is actually needed
                        $stashInfo = (object)array(
                                'pstContent' => $pstContent,
diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php
index 117e04a..7d3e804 100644
--- a/includes/parser/ParserOutput.php
+++ b/includes/parser/ParserOutput.php
@@ -53,7 +53,7 @@
                $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 = array(); # List of data updates 
objects, used to save info from the page somewhere else.
        private $mCustomDataUpdateCount = 0; # Number of custom updaters in 
$mSecondaryDataUpdates.
        private $mExtensionData = array(); # extra data used by extensions
        private $mLimitReportData = array(); # Parser limit report data
@@ -681,18 +681,23 @@
         * from the page's content. This is triggered by calling 
getSecondaryDataUpdates()
         * and is used for forward links updates on edit and backlink updates 
by jobs.
         *
-        * @note: custom DataUpdates do not survive serialization of the 
ParserOutput!
+        * @note: custom DataUpdates should survive serialization of the 
ParserOutput!
         * This is especially relevant when using a cached ParserOutput for 
updating
         * the database, as WikiPage does if $wgAjaxStashEdit is enabled. For 
this
-        * reason, ApiStashEdit will skip any ParserOutput that has custom 
DataUpdates.
+        * reason, ApiStashEdit will skip any ParserOutput that has custom 
DataUpdates
+        * that are not serializable. Use LazyDataUpdate instead of DataUpdate 
classes.
         *
         * @since 1.20
         *
-        * @param DataUpdate $update
+        * @param DataUpdate|LazyDataUpdate $update
         */
-       public function addSecondaryDataUpdate( DataUpdate $update ) {
-               $this->mSecondaryDataUpdates[] = $update;
-               $this->mCustomDataUpdateCount = count( 
$this->mSecondaryDataUpdates );
+       public function addSecondaryDataUpdate( $update ) {
+               if ( $update instanceof DataUpdate || $update instanceof 
LazyDataUpdate ) {
+                       $this->mSecondaryDataUpdates[] = $update;
+                       $this->mCustomDataUpdateCount = count( 
$this->mSecondaryDataUpdates );
+               } else {
+                       throw new Exception( "Expected DataUpdate or 
LazyDataUpdate." );
+               }
        }
 
        /**
@@ -702,9 +707,27 @@
         * @see __sleep()
         *
         * @return bool
+        * @since 1.25
         */
        public function hasCustomDataUpdates() {
                return ( $this->mCustomDataUpdateCount > 0 );
+       }
+
+       /**
+        * Check if all secondary updates are either implicit or serializable
+        *
+        * This is mostly for use by ApiEditStash
+        *
+        * @return bool
+        * @since 1.25
+        */
+       public function areSecondaryUpdatesSerializable() {
+               foreach ( $this->mSecondaryDataUpdates as $update ) {
+                       if ( ! $update instanceof LazyDataUpdate ) {
+                               return false;
+                       }
+               }
+               return true;
        }
 
        /**
@@ -735,14 +758,20 @@
                        // NOTE: This happens when mSecondaryDataUpdates are 
lost during serialization
                        // (see __sleep below). After (un)serialization, 
getSecondaryDataUpdates()
                        // has no defined behavior in that case, and should 
throw an exception.
-                       throw new MWException( 'getSecondaryDataUpdates() must 
not be called on ParserOutput restored from serialization.' );
+                       throw new MWException( 'ParserOutput derived from 
unserialization with unserializable data updates.' );
                }
 
-               // NOTE: ApiStashEdit knows about this "magic" update object. 
If this goes away,
-               // ApiStashEdit::buildStashValue needs to be adjusted.
-               $linksUpdate = new LinksUpdate( $title, $this, $recursive );
+               $updates = array();
+               foreach ( $this->mSecondaryDataUpdates as $update ) {
+                       if ( $update instanceof LazyDataUpdate ) {
+                               $updates[] = $update->resolve( $title, $this );
+                       } else {
+                               $updates[] = $update;
+                       }
+               }
+               $updates[] = new LinksUpdate( $title, $this, $recursive );
 
-               return array_merge( $this->mSecondaryDataUpdates, array( 
$linksUpdate ) );
+               return $updates;
        }
 
        /**
@@ -889,14 +918,17 @@
                return wfSetVar( $this->mPreventClickjacking, $flag );
        }
 
-       /**
-        * Save space for serialization by removing useless values
-        * @return array
-        */
-       public function __sleep() {
+       function __sleep() {
+               // Filter out updates that are not designed to be serializable.
+               // The getSecondaryDataUpdates() method knows when this 
happened.
+               $this->mSecondaryDataUpdates = array_filter(
+                       $this->mSecondaryDataUpdates,
+                       function ( $u ) { return $u instanceof LazyDataUpdate; }
+               );
+
                return array_diff(
                        array_keys( get_object_vars( $this ) ),
-                       array( 'mSecondaryDataUpdates', 'mParseStartTime' )
+                       array( 'mParseStartTime' ) // useless
                );
        }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/184463
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I9499aaf2e8501a0db8a24e244cacd9a65518a7b2
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>

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

Reply via email to