Merge "Defer the redirect table update in WikiPage::insertRedirect()"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 4 Dec 2015 19:30:05 +0000 (19:30 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 4 Dec 2015 19:30:05 +0000 (19:30 +0000)
1  2 
includes/page/WikiPage.php

@@@ -881,7 -881,8 +881,8 @@@ class WikiPage implements Page, IDBAcce
                if ( $row && !is_null( $row->rd_fragment ) && !is_null( $row->rd_interwiki ) ) {
                        $this->mRedirectTarget = Title::makeTitle(
                                $row->rd_namespace, $row->rd_title,
-                               $row->rd_fragment, $row->rd_interwiki );
+                               $row->rd_fragment, $row->rd_interwiki
+                       );
                        return $this->mRedirectTarget;
                }
  
        }
  
        /**
-        * Insert an entry for this page into the redirect table.
+        * Insert an entry for this page into the redirect table if the content is a redirect
+        *
+        * The database update will be deferred via DeferredUpdates
         *
         * Don't call this function directly unless you know what you're doing.
         * @return Title|null Title object or null if not a redirect
         */
        public function insertRedirect() {
-               // recurse through to only get the final target
                $content = $this->getContent();
                $retval = $content ? $content->getUltimateRedirectTarget() : null;
                if ( !$retval ) {
                        return null;
                }
-               $this->insertRedirectEntry( $retval );
+               // Update the DB post-send if the page has not cached since now
+               $that = $this;
+               $latest = $this->getLatest();
+               DeferredUpdates::addCallableUpdate( function() use ( $that, $retval, $latest ) {
+                       $that->insertRedirectEntry( $retval, $latest );
+               } );
                return $retval;
        }
  
        /**
-        * Insert or update the redirect table entry for this page to indicate
-        * it redirects to $rt .
+        * Insert or update the redirect table entry for this page to indicate it redirects to $rt
         * @param Title $rt Redirect target
+        * @param int|null $oldLatest Prior page_latest for check and set
         */
-       public function insertRedirectEntry( $rt ) {
+       public function insertRedirectEntry( Title $rt, $oldLatest = null ) {
                $dbw = wfGetDB( DB_MASTER );
-               $dbw->replace( 'redirect', array( 'rd_from' ),
-                       array(
-                               'rd_from' => $this->getId(),
-                               'rd_namespace' => $rt->getNamespace(),
-                               'rd_title' => $rt->getDBkey(),
-                               'rd_fragment' => $rt->getFragment(),
-                               'rd_interwiki' => $rt->getInterwiki(),
-                       ),
-                       __METHOD__
-               );
+               $dbw->startAtomic( __METHOD__ );
+               if ( !$oldLatest || $oldLatest == $this->lockAndGetLatest() ) {
+                       $dbw->replace( 'redirect',
+                               array( 'rd_from' ),
+                               array(
+                                       'rd_from' => $this->getId(),
+                                       'rd_namespace' => $rt->getNamespace(),
+                                       'rd_title' => $rt->getDBkey(),
+                                       'rd_fragment' => $rt->getFragment(),
+                                       'rd_interwiki' => $rt->getInterwiki(),
+                               ),
+                               __METHOD__
+                       );
+               }
+               $dbw->endAtomic( __METHOD__ );
        }
  
        /**
                return new UserArrayFromResult( $res );
        }
  
 -      /**
 -       * Get the last N authors
 -       * @param int $num Number of revisions to get
 -       * @param int|string $revLatest The latest rev_id, selected from the master (optional)
 -       * @return array Array of authors, duplicates not removed
 -       */
 -      public function getLastNAuthors( $num, $revLatest = 0 ) {
 -              // First try the slave
 -              // If that doesn't have the latest revision, try the master
 -              $continue = 2;
 -              $db = wfGetDB( DB_SLAVE );
 -
 -              do {
 -                      $res = $db->select( array( 'page', 'revision' ),
 -                              array( 'rev_id', 'rev_user_text' ),
 -                              array(
 -                                      'page_namespace' => $this->mTitle->getNamespace(),
 -                                      'page_title' => $this->mTitle->getDBkey(),
 -                                      'rev_page = page_id'
 -                              ), __METHOD__,
 -                              array(
 -                                      'ORDER BY' => 'rev_timestamp DESC',
 -                                      'LIMIT' => $num
 -                              )
 -                      );
 -
 -                      if ( !$res ) {
 -                              return array();
 -                      }
 -
 -                      $row = $db->fetchObject( $res );
 -
 -                      if ( $continue == 2 && $revLatest && $row->rev_id != $revLatest ) {
 -                              $db = wfGetDB( DB_MASTER );
 -                              $continue--;
 -                      } else {
 -                              $continue = 0;
 -                      }
 -              } while ( $continue );
 -
 -              $authors = array( $row->rev_user_text );
 -
 -              foreach ( $res as $row ) {
 -                      $authors[] = $row->rev_user_text;
 -              }
 -
 -              return $authors;
 -      }
 -
        /**
         * Should the parser cache be used?
         *
  
                $title = $this->mTitle;
                wfGetDB( DB_MASTER )->onTransactionIdle( function() use ( $title ) {
 -                      global $wgUseSquid;
                        // Invalidate the cache in auto-commit mode
                        $title->invalidateCache();
 -                      if ( $wgUseSquid ) {
 -                              // Send purge now that page_touched update was committed above
 -                              $update = new SquidUpdate( $title->getSquidURLs() );
 -                              $update->doUpdate();
 -                      }
                } );
  
 +              // Send purge after above page_touched update was committed
 +              DeferredUpdates::addUpdate(
 +                      new SquidUpdate( $title->getSquidURLs() ),
 +                      DeferredUpdates::PRESEND
 +              );
 +
                if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
                        // @todo move this logic to MessageCache
                        if ( $this->exists() ) {
                $isminor = ( $flags & EDIT_MINOR ) && $user->isAllowed( 'minoredit' );
                $bot = $flags & EDIT_FORCE_BOT;
  
 +              $old_revision = $this->getRevision(); // current revision
                $old_content = $this->getContent( Revision::RAW ); // current revision's content
  
                $oldsize = $old_content ? $old_content->getSize() : 0;
                                $user,
                                array(
                                        'changed' => $changed,
 -                                      'oldcountable' => $oldcountable
 +                                      'oldcountable' => $oldcountable,
 +                                      'oldrevision' => $old_revision
                                )
                        );
  
                        $this->mTimestamp = $now;
  
                        // Update links, etc.
 -                      $this->doEditUpdates( $revision, $user, array( 'created' => true ) );
 +                      $this->doEditUpdates(
 +                              $revision,
 +                              $user,
 +                              array( 'created' => true, 'oldrevision' => $old_revision )
 +                      );
  
                        $hook_args = array( &$this, &$user, $content, $summary,
                                                                $flags & EDIT_MINOR, null, null, &$flags, $revision );
         * - changed: boolean, whether the revision changed the content (default true)
         * - created: boolean, whether the revision created the page (default false)
         * - moved: boolean, whether the page was moved (default false)
 +       * - restored: boolean, whether the page was undeleted (default false)
 +       * - oldrevision: Revision object for the pre-update revision (default null)
         * - oldcountable: boolean, null, or string 'no-change' (default null):
         *   - boolean: whether the page was counted as an article before that
         *     revision, only used in changed is true and created is false
         *   - 'no-change': don't update the article count, ever
         */
        public function doEditUpdates( Revision $revision, User $user, array $options = array() ) {
 +              global $wgRCWatchCategoryMembership;
 +
                $options += array(
                        'changed' => true,
                        'created' => false,
                        'moved' => false,
 +                      'restored' => false,
 +                      'oldrevision' => null,
                        'oldcountable' => null
                );
                $content = $revision->getContent();
                if ( $content ) {
                        $recursive = $options['changed']; // bug 50785
                        $updates = $content->getSecondaryDataUpdates(
 -                              $this->getTitle(), null, $recursive, $editInfo->output );
 +                              $this->getTitle(), null, $recursive, $editInfo->output
 +                      );
                        foreach ( $updates as $update ) {
                                if ( $update instanceof LinksUpdate ) {
                                        $update->setRevision( $revision );
                                }
                                DeferredUpdates::addUpdate( $update );
                        }
 +                      if ( $wgRCWatchCategoryMembership
 +                              && ( $options['changed'] || $options['created'] )
 +                              && !$options['restored']
 +                      ) {
 +                              // Note: jobs are pushed after deferred updates, so the job should be able to see
 +                              // the recent change entry (also done via deferred updates) and carry over any
 +                              // bot/deletion/IP flags, ect.
 +                              JobQueueGroup::singleton()->lazyPush( new CategoryMembershipChangeJob(
 +                                      $this->getTitle(),
 +                                      array(
 +                                              'pageId' => $this->getId(),
 +                                              'revTimestamp' => $revision->getTimestamp()
 +                                      )
 +                              ) );
 +                      }
                }
  
                Hooks::run( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );