Merge "parser: inject the time for {{REVISIONTIMESTAMP}} on pre-save parse"
[lhc/web/wiklou.git] / includes / Storage / DerivedPageDataUpdater.php
index 5f7401a..b4d6f05 100644 (file)
@@ -48,6 +48,7 @@ use MediaWiki\Revision\SlotRoleRegistry;
 use MediaWiki\Revision\SlotRecord;
 use MediaWiki\User\UserIdentity;
 use MessageCache;
+use MWCallableUpdate;
 use ParserCache;
 use ParserOptions;
 use ParserOutput;
@@ -62,7 +63,7 @@ use SiteStatsUpdate;
 use Title;
 use User;
 use Wikimedia\Assert\Assert;
-use Wikimedia\Rdbms\LBFactory;
+use Wikimedia\Rdbms\ILBFactory;
 use WikiPage;
 
 /**
@@ -134,7 +135,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
        private $messageCache;
 
        /**
-        * @var LBFactory
+        * @var ILBFactory
         */
        private $loadbalancerFactory;
 
@@ -275,7 +276,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
         * @param JobQueueGroup $jobQueueGroup
         * @param MessageCache $messageCache
         * @param Language $contLang
-        * @param LBFactory $loadbalancerFactory
+        * @param ILBFactory $loadbalancerFactory
         */
        public function __construct(
                WikiPage $wikiPage,
@@ -286,7 +287,7 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
                JobQueueGroup $jobQueueGroup,
                MessageCache $messageCache,
                Language $contLang,
-               LBFactory $loadbalancerFactory
+               ILBFactory $loadbalancerFactory
        ) {
                $this->wikiPage = $wikiPage;
 
@@ -1437,12 +1438,18 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
                }
 
                // Defer the getCannonicalParserOutput() call triggered by getSecondaryDataUpdates()
-               DeferredUpdates::addCallableUpdate( function () {
-                       $this->doSecondaryDataUpdates( [
-                               // T52785 do not update any other pages on a null edit
-                               'recursive' => $this->options['changed']
-                       ] );
-               } );
+               // by wrapping the code that schedules the secondary updates in a callback itself
+               $wrapperUpdate = new MWCallableUpdate(
+                       function () {
+                               $this->doSecondaryDataUpdates( [
+                                       // T52785 do not update any other pages on a null edit
+                                       'recursive' => $this->options['changed']
+                               ] );
+                       },
+                       __METHOD__
+               );
+               $wrapperUpdate->setTransactionRoundRequirement( $wrapperUpdate::TRX_ROUND_ABSENT );
+               DeferredUpdates::addUpdate( $wrapperUpdate );
 
                // TODO: MCR: check if *any* changed slot supports categories!
                if ( $this->rcWatchCategoryMembership
@@ -1583,24 +1590,15 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
         *     current page or otherwise depend on it (default: false)
         *   - defer: one of the DeferredUpdates constants, or false to run immediately after waiting
         *     for replication of the changes from the SecondaryDataUpdates hooks (default: false)
-        *   - transactionTicket: a transaction ticket from LBFactory::getEmptyTransactionTicket(),
-        *     only when defer is false (default: null)
         * @since 1.32
         */
        public function doSecondaryDataUpdates( array $options = [] ) {
                $this->assertHasRevision( __METHOD__ );
-               $options += [
-                       'recursive' => false,
-                       'defer' => false,
-                       'transactionTicket' => null,
-               ];
+               $options += [ 'recursive' => false, 'defer' => false ];
                $deferValues = [ false, DeferredUpdates::PRESEND, DeferredUpdates::POSTSEND ];
                if ( !in_array( $options['defer'], $deferValues, true ) ) {
                        throw new InvalidArgumentException( 'Invalid value for defer: ' . $options['defer'] );
                }
-               Assert::parameterType(
-                       'integer|null', $options['transactionTicket'], '$options[\'transactionTicket\']' );
-
                $updates = $this->getSecondaryDataUpdates( $options['recursive'] );
 
                $triggeringUser = $this->options['triggeringUser'] ?? $this->user;
@@ -1610,14 +1608,6 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
                $causeAction = $this->options['causeAction'] ?? 'unknown';
                $causeAgent = $this->options['causeAgent'] ?? 'unknown';
                $legacyRevision = new Revision( $this->revision );
-               $ticket = $options['transactionTicket'];
-
-               if ( $options['defer'] === false && $ticket !== null ) {
-                       // For legacy hook handlers doing updates via LinksUpdateConstructed, make sure
-                       // any pending writes they made get flushed before the doUpdate() calls below.
-                       // This avoids snapshot-clearing errors in LinksUpdate::acquirePageLock().
-                       $this->loadbalancerFactory->commitAndWaitForReplication( __METHOD__, $ticket );
-               }
 
                foreach ( $updates as $update ) {
                        if ( $update instanceof DataUpdate ) {
@@ -1627,13 +1617,16 @@ class DerivedPageDataUpdater implements IDBAccessObject, LoggerAwareInterface {
                                $update->setRevision( $legacyRevision );
                                $update->setTriggeringUser( $triggeringUser );
                        }
+               }
 
-                       if ( $options['defer'] === false ) {
-                               if ( $update instanceof DataUpdate && $ticket !== null ) {
-                                       $update->setTransactionTicket( $ticket );
-                               }
-                               $update->doUpdate();
-                       } else {
+               if ( $options['defer'] === false ) {
+                       // T221577: flush any transaction; each update needs outer transaction scope
+                       $this->loadbalancerFactory->commitMasterChanges( __METHOD__ );
+                       foreach ( $updates as $update ) {
+                               DeferredUpdates::attemptUpdate( $update, $this->loadbalancerFactory );
+                       }
+               } else {
+                       foreach ( $updates as $update ) {
                                DeferredUpdates::addUpdate( $update, $options['defer'] );
                        }
                }