Merge "Re-namespace RevisionStore and RevisionRecord classes"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 10 Oct 2018 05:16:45 +0000 (05:16 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 10 Oct 2018 05:16:45 +0000 (05:16 +0000)
1  2 
autoload.php
includes/page/Article.php
includes/page/WikiPage.php

diff --combined autoload.php
@@@ -384,7 -384,6 +384,7 @@@ $wgAutoloadLocalClasses = 
        'DeleteLogFormatter' => __DIR__ . '/includes/logging/DeleteLogFormatter.php',
        'DeleteOldRevisions' => __DIR__ . '/maintenance/deleteOldRevisions.php',
        'DeleteOrphanedRevisions' => __DIR__ . '/maintenance/deleteOrphanedRevisions.php',
 +      'DeletePageJob' => __DIR__ . '/includes/jobqueue/jobs/DeletePageJob.php',
        'DeleteSelfExternals' => __DIR__ . '/maintenance/deleteSelfExternals.php',
        'DeletedContribsPager' => __DIR__ . '/includes/specials/pagers/DeletedContribsPager.php',
        'DeletedContributionsPage' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
        'MediaWiki\\MediaWikiServices' => __DIR__ . '/includes/MediaWikiServices.php',
        'MediaWiki\\OutputHandler' => __DIR__ . '/includes/OutputHandler.php',
        'MediaWiki\\ProcOpenError' => __DIR__ . '/includes/exception/ProcOpenError.php',
-       'MediaWiki\\Revision\\RenderedRevision' => __DIR__ . '/includes/Revision/RenderedRevision.php',
-       'MediaWiki\\Revision\\RevisionRenderer' => __DIR__ . '/includes/Revision/RevisionRenderer.php',
-       'MediaWiki\\Revision\\SlotRenderingProvider' => __DIR__ . '/includes/Revision/SlotRenderingProvider.php',
        'MediaWiki\\Search\\ParserOutputSearchDataExtractor' => __DIR__ . '/includes/search/ParserOutputSearchDataExtractor.php',
        'MediaWiki\\ShellDisabledError' => __DIR__ . '/includes/exception/ShellDisabledError.php',
        'MediaWiki\\Site\\MediaWikiPageNameNormalizer' => __DIR__ . '/includes/site/MediaWikiPageNameNormalizer.php',
        'MediaWiki\\Special\\SpecialPageFactory' => __DIR__ . '/includes/specialpage/SpecialPageFactory.php',
+       'MediaWiki\\Storage\\IncompleteRevisionException' => __DIR__ . '/includes/Revision/IncompleteRevisionException.php',
+       'MediaWiki\\Storage\\MutableRevisionRecord' => __DIR__ . '/includes/Revision/MutableRevisionRecord.php',
+       'MediaWiki\\Storage\\MutableRevisionSlots' => __DIR__ . '/includes/Revision/MutableRevisionSlots.php',
+       'MediaWiki\\Storage\\RevisionAccessException' => __DIR__ . '/includes/Revision/RevisionAccessException.php',
+       'MediaWiki\\Storage\\RevisionArchiveRecord' => __DIR__ . '/includes/Revision/RevisionArchiveRecord.php',
+       'MediaWiki\\Storage\\RevisionFactory' => __DIR__ . '/includes/Revision/RevisionFactory.php',
+       'MediaWiki\\Storage\\RevisionLookup' => __DIR__ . '/includes/Revision/RevisionLookup.php',
+       'MediaWiki\\Storage\\RevisionRecord' => __DIR__ . '/includes/Revision/RevisionRecord.php',
+       'MediaWiki\\Storage\\RevisionSlots' => __DIR__ . '/includes/Revision/RevisionSlots.php',
+       'MediaWiki\\Storage\\RevisionStore' => __DIR__ . '/includes/Revision/RevisionStore.php',
+       'MediaWiki\\Storage\\RevisionStoreRecord' => __DIR__ . '/includes/Revision/RevisionStoreRecord.php',
+       'MediaWiki\\Storage\\SlotRecord' => __DIR__ . '/includes/Revision/SlotRecord.php',
+       'MediaWiki\\Storage\\SuppressedDataException' => __DIR__ . '/includes/Revision/SuppressedDataException.php',
        'MediaWiki\\User\\UserIdentity' => __DIR__ . '/includes/user/UserIdentity.php',
        'MediaWiki\\User\\UserIdentityValue' => __DIR__ . '/includes/user/UserIdentityValue.php',
        'MediaWiki\\Widget\\CheckMatrixWidget' => __DIR__ . '/includes/widget/CheckMatrixWidget.php',
@@@ -20,9 -20,9 +20,9 @@@
   * @file
   */
  use MediaWiki\MediaWikiServices;
- use MediaWiki\Storage\MutableRevisionRecord;
- use MediaWiki\Storage\RevisionRecord;
- use MediaWiki\Storage\SlotRecord;
+ use MediaWiki\Revision\MutableRevisionRecord;
+ use MediaWiki\Revision\RevisionRecord;
+ use MediaWiki\Revision\SlotRecord;
  
  /**
   * Class for viewing MediaWiki article and history.
@@@ -2053,31 -2053,25 +2053,31 @@@ class Article implements Page 
         * Perform a deletion and output success or failure messages
         * @param string $reason
         * @param bool $suppress
 +       * @param bool $immediate false allows deleting over time via the job queue
 +       * @throws FatalError
 +       * @throws MWException
         */
 -      public function doDelete( $reason, $suppress = false ) {
 +      public function doDelete( $reason, $suppress = false, $immediate = false ) {
                $error = '';
                $context = $this->getContext();
                $outputPage = $context->getOutput();
                $user = $context->getUser();
 -              $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error, $user );
 +              $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error, $user,
 +                      [], 'delete', $immediate );
  
 -              if ( $status->isGood() ) {
 +              if ( $status->isOK() ) {
                        $deleted = $this->getTitle()->getPrefixedText();
  
                        $outputPage->setPageTitle( wfMessage( 'actioncomplete' ) );
                        $outputPage->setRobotPolicy( 'noindex,nofollow' );
  
 -                      $loglink = '[[Special:Log/delete|' . wfMessage( 'deletionlog' )->text() . ']]';
 -
 -                      $outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
 -
 -                      Hooks::run( 'ArticleDeleteAfterSuccess', [ $this->getTitle(), $outputPage ] );
 +                      if ( $status->isGood() ) {
 +                              $loglink = '[[Special:Log/delete|' . wfMessage( 'deletionlog' )->text() . ']]';
 +                              $outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
 +                              Hooks::run( 'ArticleDeleteAfterSuccess', [ $this->getTitle(), $outputPage ] );
 +                      } else {
 +                              $outputPage->addWikiMsg( 'delete-scheduled', wfEscapeWikiText( $deleted ) );
 +                      }
  
                        $outputPage->returnToMain( false );
                } else {
         */
        public function doDeleteArticleReal(
                $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null,
 -              $tags = []
 +              $tags = [], $immediate = false
        ) {
                return $this->mPage->doDeleteArticleReal(
 -                      $reason, $suppress, $u1, $u2, $error, $user, $tags
 +                      $reason, $suppress, $u1, $u2, $error, $user, $tags, 'delete', $immediate
                );
        }
  
         * @param int|null $u1 Unused
         * @param bool|null $u2 Unused
         * @param string &$error
 +       * @param bool $immediate false allows deleting over time via the job queue
         * @return bool
 +       * @throws FatalError
 +       * @throws MWException
         */
        public function doDeleteArticle(
 -              $reason, $suppress = false, $u1 = null, $u2 = null, &$error = ''
 +              $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', $immediate = false
        ) {
 -              return $this->mPage->doDeleteArticle( $reason, $suppress, $u1, $u2, $error );
 +              return $this->mPage->doDeleteArticle( $reason, $suppress, $u1, $u2, $error,
 +                      null, $immediate );
        }
  
        /**
  use MediaWiki\Edit\PreparedEdit;
  use MediaWiki\Logger\LoggerFactory;
  use MediaWiki\MediaWikiServices;
+ use MediaWiki\Revision\RevisionRecord;
  use MediaWiki\Revision\RevisionRenderer;
+ use MediaWiki\Revision\RevisionStore;
+ use MediaWiki\Revision\SlotRecord;
  use MediaWiki\Storage\DerivedPageDataUpdater;
  use MediaWiki\Storage\PageUpdater;
- use MediaWiki\Storage\RevisionRecord;
  use MediaWiki\Storage\RevisionSlotsUpdate;
- use MediaWiki\Storage\RevisionStore;
- use MediaWiki\Storage\SlotRecord;
  use Wikimedia\Assert\Assert;
  use Wikimedia\Rdbms\FakeResultWrapper;
  use Wikimedia\Rdbms\IDatabase;
@@@ -2512,28 -2512,6 +2512,28 @@@ class WikiPage implements Page, IDBAcce
                return implode( ':', $bits );
        }
  
 +      /**
 +       * Determines if deletion of this page would be batched (executed over time by the job queue)
 +       * or not (completed in the same request as the delete call).
 +       *
 +       * It is unlikely but possible that an edit from another request could push the page over the
 +       * batching threshold after this function is called, but before the caller acts upon the
 +       * return value.  Callers must decide for themselves how to deal with this.  $safetyMargin
 +       * is provided as an unreliable but situationally useful help for some common cases.
 +       *
 +       * @param int $safetyMargin Added to the revision count when checking for batching
 +       * @return bool True if deletion would be batched, false otherwise
 +       */
 +      public function isBatchedDelete( $safetyMargin = 0 ) {
 +              global $wgDeleteRevisionsBatchSize;
 +
 +              $dbr = wfGetDB( DB_REPLICA );
 +              $revCount = $this->getRevisionStore()->countRevisionsByPageId( $dbr, $this->getId() );
 +              $revCount += $safetyMargin;
 +
 +              return $revCount >= $wgDeleteRevisionsBatchSize;
 +      }
 +
        /**
         * Same as doDeleteArticleReal(), but returns a simple boolean. This is kept around for
         * backwards compatibility, if you care about error reporting you should use
         * @param bool|null $u2 Unused
         * @param array|string &$error Array of errors to append to
         * @param User|null $user The deleting user
 +       * @param bool $immediate false allows deleting over time via the job queue
         * @return bool True if successful
 +       * @throws FatalError
 +       * @throws MWException
         */
        public function doDeleteArticle(
 -              $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null
 +              $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $user = null,
 +              $immediate = false
        ) {
 -              $status = $this->doDeleteArticleReal( $reason, $suppress, $u1, $u2, $error, $user );
 -              return $status->isGood();
 +              $status = $this->doDeleteArticleReal( $reason, $suppress, $u1, $u2, $error, $user,
 +                      [], 'delete', $immediate );
 +
 +              // Returns true if the page was actually deleted, or is scheduled for deletion
 +              return $status->isOK();
        }
  
        /**
         * @param User|null $deleter The deleting user
         * @param array $tags Tags to apply to the deletion action
         * @param string $logsubtype
 +       * @param bool $immediate false allows deleting over time via the job queue
         * @return Status Status object; if successful, $status->value is the log_id of the
         *   deletion log entry. If the page couldn't be deleted because it wasn't
         *   found, $status is a non-fatal 'cannotdelete' error
 +       * @throws FatalError
 +       * @throws MWException
         */
        public function doDeleteArticleReal(
                $reason, $suppress = false, $u1 = null, $u2 = null, &$error = '', User $deleter = null,
 -              $tags = [], $logsubtype = 'delete'
 +              $tags = [], $logsubtype = 'delete', $immediate = false
        ) {
 -              global $wgUser, $wgContentHandlerUseDB, $wgCommentTableSchemaMigrationStage,
 -                      $wgActorTableSchemaMigrationStage, $wgMultiContentRevisionSchemaMigrationStage;
 +              global $wgUser;
  
                wfDebug( __METHOD__ . "\n" );
  
                $status = Status::newGood();
  
 -              if ( $this->mTitle->getDBkey() === '' ) {
 -                      $status->error( 'cannotdelete',
 -                              wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
 -                      return $status;
 -              }
 -
                // Avoid PHP 7.1 warning of passing $this by reference
                $wikiPage = $this;
  
                        return $status;
                }
  
 +              return $this->doDeleteArticleBatched( $reason, $suppress, $deleter, $tags,
 +                      $logsubtype, $immediate );
 +      }
 +
 +      /**
 +       * Back-end article deletion
 +       *
 +       * Only invokes batching via the job queue if necessary per $wgDeleteRevisionsBatchSize.
 +       * Deletions can often be completed inline without involving the job queue.
 +       *
 +       * Potentially called many times per deletion operation for pages with many revisions.
 +       */
 +      public function doDeleteArticleBatched(
 +              $reason, $suppress, User $deleter, $tags,
 +              $logsubtype, $immediate = false, $webRequestId = null
 +      ) {
 +              wfDebug( __METHOD__ . "\n" );
 +
 +              $status = Status::newGood();
 +
                $dbw = wfGetDB( DB_MASTER );
                $dbw->startAtomic( __METHOD__ );
  
                        return $status;
                }
  
 -              // Given the lock above, we can be confident in the title and page ID values
 -              $namespace = $this->getTitle()->getNamespace();
 -              $dbKey = $this->getTitle()->getDBkey();
 -
 -              // At this point we are now comitted to returning an OK
 +              // At this point we are now committed to returning an OK
                // status unless some DB query error or other exception comes up.
                // This way callers don't have to call rollback() if $status is bad
                // unless they actually try to catch exceptions (which is rare).
                        $content = null;
                }
  
 +              // Archive revisions.  In immediate mode, archive all revisions.  Otherwise, archive
 +              // one batch of revisions and defer archival of any others to the job queue.
 +              $explictTrxLogged = false;
 +              while ( true ) {
 +                      $done = $this->archiveRevisions( $dbw, $id, $suppress );
 +                      if ( $done || !$immediate ) {
 +                              break;
 +                      }
 +                      $dbw->endAtomic( __METHOD__ );
 +                      if ( $dbw->explicitTrxActive() ) {
 +                              // Explict transactions may never happen here in practice.  Log to be sure.
 +                              if ( !$explictTrxLogged ) {
 +                                      $explictTrxLogged = true;
 +                                      LoggerFactory::getInstance( 'wfDebug' )->debug(
 +                                              'explicit transaction active in ' . __METHOD__ . ' while deleting {title}', [
 +                                              'title' => $this->getTitle()->getText(),
 +                                      ] );
 +                              }
 +                              continue;
 +                      }
 +                      if ( $dbw->trxLevel() ) {
 +                              $dbw->commit();
 +                      }
 +                      $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
 +                      $lbFactory->waitForReplication();
 +                      $dbw->startAtomic( __METHOD__ );
 +              }
 +
 +              // If done archiving, also delete the article.
 +              if ( !$done ) {
 +                      $dbw->endAtomic( __METHOD__ );
 +
 +                      $jobParams = [
 +                              'wikiPageId' => $id,
 +                              'requestId' => $webRequestId ?? WebRequest::getRequestId(),
 +                              'reason' => $reason,
 +                              'suppress' => $suppress,
 +                              'userId' => $deleter->getId(),
 +                              'tags' => json_encode( $tags ),
 +                              'logsubtype' => $logsubtype,
 +                      ];
 +
 +                      $job = new DeletePageJob( $this->getTitle(), $jobParams );
 +                      JobQueueGroup::singleton()->push( $job );
 +
 +                      $status->warning( 'delete-scheduled',
 +                              wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
 +              } else {
 +                      // Get archivedRevisionCount by db query, because there's no better alternative.
 +                      // Jobs cannot pass a count of archived revisions to the next job, because additional
 +                      // deletion operations can be started while the first is running.  Jobs from each
 +                      // gracefully interleave, but would not know about each other's count.  Deduplication
 +                      // in the job queue to avoid simultaneous deletion operations would add overhead.
 +                      // Number of archived revisions cannot be known beforehand, because edits can be made
 +                      // while deletion operations are being processed, changing the number of archivals.
 +                      $archivedRevisionCount = $dbw->selectRowCount(
 +                              'archive', '1', [ 'ar_page_id' => $id ], __METHOD__
 +                      );
 +
 +                      // Clone the title and wikiPage, so we have the information we need when
 +                      // we log and run the ArticleDeleteComplete hook.
 +                      $logTitle = clone $this->mTitle;
 +                      $wikiPageBeforeDelete = clone $this;
 +
 +                      // Now that it's safely backed up, delete it
 +                      $dbw->delete( 'page', [ 'page_id' => $id ], __METHOD__ );
 +
 +                      // Log the deletion, if the page was suppressed, put it in the suppression log instead
 +                      $logtype = $suppress ? 'suppress' : 'delete';
 +
 +                      $logEntry = new ManualLogEntry( $logtype, $logsubtype );
 +                      $logEntry->setPerformer( $deleter );
 +                      $logEntry->setTarget( $logTitle );
 +                      $logEntry->setComment( $reason );
 +                      $logEntry->setTags( $tags );
 +                      $logid = $logEntry->insert();
 +
 +                      $dbw->onTransactionPreCommitOrIdle(
 +                              function () use ( $logEntry, $logid ) {
 +                                      // T58776: avoid deadlocks (especially from FileDeleteForm)
 +                                      $logEntry->publish( $logid );
 +                              },
 +                              __METHOD__
 +                      );
 +
 +                      $dbw->endAtomic( __METHOD__ );
 +
 +                      $this->doDeleteUpdates( $id, $content, $revision, $deleter );
 +
 +                      Hooks::run( 'ArticleDeleteComplete', [
 +                              &$wikiPageBeforeDelete,
 +                              &$deleter,
 +                              $reason,
 +                              $id,
 +                              $content,
 +                              $logEntry,
 +                              $archivedRevisionCount
 +                      ] );
 +                      $status->value = $logid;
 +
 +                      // Show log excerpt on 404 pages rather than just a link
 +                      $cache = MediaWikiServices::getInstance()->getMainObjectStash();
 +                      $key = $cache->makeKey( 'page-recent-delete', md5( $logTitle->getPrefixedText() ) );
 +                      $cache->set( $key, 1, $cache::TTL_DAY );
 +              }
 +
 +              return $status;
 +      }
 +
 +      /**
 +       * Archives revisions as part of page deletion.
 +       *
 +       * @param IDatabase $dbw
 +       * @param int $id
 +       * @param bool $suppress Suppress all revisions and log the deletion in
 +       *   the suppression log instead of the deletion log
 +       * @return bool
 +       */
 +      protected function archiveRevisions( $dbw, $id, $suppress ) {
 +              global $wgContentHandlerUseDB, $wgMultiContentRevisionSchemaMigrationStage,
 +                      $wgCommentTableSchemaMigrationStage, $wgActorTableSchemaMigrationStage,
 +                      $wgDeleteRevisionsBatchSize;
 +
 +              // Given the lock above, we can be confident in the title and page ID values
 +              $namespace = $this->getTitle()->getNamespace();
 +              $dbKey = $this->getTitle()->getDBkey();
 +
                $commentStore = CommentStore::getStore();
                $actorMigration = ActorMigration::newMigration();
  
                        }
                }
  
 -                      // Get all of the page revisions
 +              // Get as many of the page revisions as we are allowed to.  The +1 lets us recognize the
 +              // unusual case where there were exactly $wgDeleteRevisionBatchSize revisions remaining.
                $res = $dbw->select(
                        $revQuery['tables'],
                        $revQuery['fields'],
                        [ 'rev_page' => $id ],
                        __METHOD__,
 -                      [],
 +                      [ 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => $wgDeleteRevisionsBatchSize + 1 ],
                        $revQuery['joins']
                );
  
                /** @var int[] Revision IDs of edits that were made by IPs */
                $ipRevIds = [];
  
 +              $done = true;
                foreach ( $res as $row ) {
 +                      if ( count( $revids ) >= $wgDeleteRevisionsBatchSize ) {
 +                              $done = false;
 +                              break;
 +                      }
 +
                        $comment = $commentStore->getComment( 'rev_comment', $row );
                        $user = User::newFromAnyId( $row->rev_user, $row->rev_user_text, $row->rev_actor );
                        $rowInsert = [
 -                              'ar_namespace'  => $namespace,
 -                              'ar_title'      => $dbKey,
 -                              'ar_timestamp'  => $row->rev_timestamp,
 -                              'ar_minor_edit' => $row->rev_minor_edit,
 -                              'ar_rev_id'     => $row->rev_id,
 -                              'ar_parent_id'  => $row->rev_parent_id,
 +                                      'ar_namespace'  => $namespace,
 +                                      'ar_title'      => $dbKey,
 +                                      'ar_timestamp'  => $row->rev_timestamp,
 +                                      'ar_minor_edit' => $row->rev_minor_edit,
 +                                      'ar_rev_id'     => $row->rev_id,
 +                                      'ar_parent_id'  => $row->rev_parent_id,
                                        /**
                                         * ar_text_id should probably not be written to when the multi content schema has
                                         * been migrated to (wgMultiContentRevisionSchemaMigrationStage) however there is no
                                         * Task: https://phabricator.wikimedia.org/T190148
                                         * Copying the value from the revision table should not lead to any issues for now.
                                         */
 -                              'ar_len'        => $row->rev_len,
 -                              'ar_page_id'    => $id,
 -                              'ar_deleted'    => $suppress ? $bitfield : $row->rev_deleted,
 -                              'ar_sha1'       => $row->rev_sha1,
 -                      ] + $commentStore->insert( $dbw, 'ar_comment', $comment )
 +                                      'ar_len'        => $row->rev_len,
 +                                      'ar_page_id'    => $id,
 +                                      'ar_deleted'    => $suppress ? $bitfield : $row->rev_deleted,
 +                                      'ar_sha1'       => $row->rev_sha1,
 +                              ] + $commentStore->insert( $dbw, 'ar_comment', $comment )
                                + $actorMigration->getInsertValues( $dbw, 'ar_user', $user );
  
                        if ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) {
                                $ipRevIds[] = $row->rev_id;
                        }
                }
 -              // Copy them into the archive table
 -              $dbw->insert( 'archive', $rowsInsert, __METHOD__ );
 -              // Save this so we can pass it to the ArticleDeleteComplete hook.
 -              $archivedRevisionCount = $dbw->affectedRows();
  
 -              // Clone the title and wikiPage, so we have the information we need when
 -              // we log and run the ArticleDeleteComplete hook.
 -              $logTitle = clone $this->mTitle;
 -              $wikiPageBeforeDelete = clone $this;
 +              // This conditional is just a sanity check
 +              if ( count( $revids ) > 0 ) {
 +                      // Copy them into the archive table
 +                      $dbw->insert( 'archive', $rowsInsert, __METHOD__ );
  
 -              // Now that it's safely backed up, delete it
 -              $dbw->delete( 'page', [ 'page_id' => $id ], __METHOD__ );
 -              $dbw->delete( 'revision', [ 'rev_page' => $id ], __METHOD__ );
 -              if ( $wgCommentTableSchemaMigrationStage > MIGRATION_OLD ) {
 -                      $dbw->delete( 'revision_comment_temp', [ 'revcomment_rev' => $revids ], __METHOD__ );
 -              }
 -              if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
 -                      $dbw->delete( 'revision_actor_temp', [ 'revactor_rev' => $revids ], __METHOD__ );
 -              }
 +                      $dbw->delete( 'revision', [ 'rev_id' => $revids ], __METHOD__ );
 +                      if ( $wgCommentTableSchemaMigrationStage > MIGRATION_OLD ) {
 +                              $dbw->delete( 'revision_comment_temp', [ 'revcomment_rev' => $revids ], __METHOD__ );
 +                      }
 +                      if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
 +                              $dbw->delete( 'revision_actor_temp', [ 'revactor_rev' => $revids ], __METHOD__ );
 +                      }
  
 -              // Also delete records from ip_changes as applicable.
 -              if ( count( $ipRevIds ) > 0 ) {
 -                      $dbw->delete( 'ip_changes', [ 'ipc_rev_id' => $ipRevIds ], __METHOD__ );
 +                      // Also delete records from ip_changes as applicable.
 +                      if ( count( $ipRevIds ) > 0 ) {
 +                              $dbw->delete( 'ip_changes', [ 'ipc_rev_id' => $ipRevIds ], __METHOD__ );
 +                      }
                }
  
 -              // Log the deletion, if the page was suppressed, put it in the suppression log instead
 -              $logtype = $suppress ? 'suppress' : 'delete';
 -
 -              $logEntry = new ManualLogEntry( $logtype, $logsubtype );
 -              $logEntry->setPerformer( $deleter );
 -              $logEntry->setTarget( $logTitle );
 -              $logEntry->setComment( $reason );
 -              $logEntry->setTags( $tags );
 -              $logid = $logEntry->insert();
 -
 -              $dbw->onTransactionPreCommitOrIdle(
 -                      function () use ( $logEntry, $logid ) {
 -                              // T58776: avoid deadlocks (especially from FileDeleteForm)
 -                              $logEntry->publish( $logid );
 -                      },
 -                      __METHOD__
 -              );
 -
 -              $dbw->endAtomic( __METHOD__ );
 -
 -              $this->doDeleteUpdates( $id, $content, $revision, $deleter );
 -
 -              Hooks::run( 'ArticleDeleteComplete', [
 -                      &$wikiPageBeforeDelete,
 -                      &$deleter,
 -                      $reason,
 -                      $id,
 -                      $content,
 -                      $logEntry,
 -                      $archivedRevisionCount
 -              ] );
 -              $status->value = $logid;
 -
 -              // Show log excerpt on 404 pages rather than just a link
 -              $cache = MediaWikiServices::getInstance()->getMainObjectStash();
 -              $key = $cache->makeKey( 'page-recent-delete', md5( $logTitle->getPrefixedText() ) );
 -              $cache->set( $key, 1, $cache::TTL_DAY );
 -
 -              return $status;
 +              return $done;
        }
  
        /**