Merge "Moved RecentChange::purgeExpiredChanges to a job"
[lhc/web/wiklou.git] / includes / page / WikiPage.php
index 7de7f27..2f900f9 100644 (file)
@@ -557,7 +557,6 @@ class WikiPage implements Page, IDBAccessObject {
         * @return Revision|null
         */
        public function getOldestRevision() {
-               wfProfileIn( __METHOD__ );
 
                // Try using the slave database first, then try the master
                $continue = 2;
@@ -588,7 +587,6 @@ class WikiPage implements Page, IDBAccessObject {
                        }
                }
 
-               wfProfileOut( __METHOD__ );
                return $row ? Revision::newFromRow( $row ) : null;
        }
 
@@ -1055,7 +1053,6 @@ class WikiPage implements Page, IDBAccessObject {
         * @return array Array of authors, duplicates not removed
         */
        public function getLastNAuthors( $num, $revLatest = 0 ) {
-               wfProfileIn( __METHOD__ );
                // First try the slave
                // If that doesn't have the latest revision, try the master
                $continue = 2;
@@ -1076,7 +1073,6 @@ class WikiPage implements Page, IDBAccessObject {
                        );
 
                        if ( !$res ) {
-                               wfProfileOut( __METHOD__ );
                                return array();
                        }
 
@@ -1096,7 +1092,6 @@ class WikiPage implements Page, IDBAccessObject {
                        $authors[] = $row->rev_user_text;
                }
 
-               wfProfileOut( __METHOD__ );
                return $authors;
        }
 
@@ -1129,7 +1124,6 @@ class WikiPage implements Page, IDBAccessObject {
         * @return ParserOutput|bool ParserOutput or false if the revision was not found
         */
        public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) {
-               wfProfileIn( __METHOD__ );
 
                $useParserCache = $this->isParserCacheUsed( $parserOptions, $oldid );
                wfDebug( __METHOD__ . ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
@@ -1140,7 +1134,6 @@ class WikiPage implements Page, IDBAccessObject {
                if ( $useParserCache ) {
                        $parserOutput = ParserCache::singleton()->get( $this, $parserOptions );
                        if ( $parserOutput !== false ) {
-                               wfProfileOut( __METHOD__ );
                                return $parserOutput;
                        }
                }
@@ -1152,8 +1145,6 @@ class WikiPage implements Page, IDBAccessObject {
                $pool = new PoolWorkArticleView( $this, $parserOptions, $oldid, $useParserCache );
                $pool->execute();
 
-               wfProfileOut( __METHOD__ );
-
                return $pool->getParserOutput();
        }
 
@@ -1228,7 +1219,6 @@ class WikiPage implements Page, IDBAccessObject {
         * @return int The newly created page_id key, or false if the title already existed
         */
        public function insertOn( $dbw ) {
-               wfProfileIn( __METHOD__ );
 
                $page_id = $dbw->nextSequenceValue( 'page_page_id_seq' );
                $dbw->insert( 'page', array(
@@ -1251,7 +1241,6 @@ class WikiPage implements Page, IDBAccessObject {
                        $this->mId = $newid;
                        $this->mTitle->resetArticleID( $newid );
                }
-               wfProfileOut( __METHOD__ );
 
                return $affected ? $newid : false;
        }
@@ -1274,8 +1263,6 @@ class WikiPage implements Page, IDBAccessObject {
        ) {
                global $wgContentHandlerUseDB;
 
-               wfProfileIn( __METHOD__ );
-
                $content = $revision->getContent();
                $len = $content ? $content->getSize() : 0;
                $rt = $content ? $content->getUltimateRedirectTarget() : null;
@@ -1317,7 +1304,6 @@ class WikiPage implements Page, IDBAccessObject {
                                                                                                        $this->mLatest, $revision->getContentModel() );
                }
 
-               wfProfileOut( __METHOD__ );
                return $result;
        }
 
@@ -1342,7 +1328,6 @@ class WikiPage implements Page, IDBAccessObject {
                        return true;
                }
 
-               wfProfileIn( __METHOD__ );
                if ( $isRedirect ) {
                        $this->insertRedirectEntry( $redirectTitle );
                } else {
@@ -1354,7 +1339,6 @@ class WikiPage implements Page, IDBAccessObject {
                if ( $this->getTitle()->getNamespace() == NS_FILE ) {
                        RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $this->getTitle() );
                }
-               wfProfileOut( __METHOD__ );
 
                return ( $dbw->affectedRows() != 0 );
        }
@@ -1370,7 +1354,6 @@ class WikiPage implements Page, IDBAccessObject {
         * @return bool
         */
        public function updateIfNewerOn( $dbw, $revision ) {
-               wfProfileIn( __METHOD__ );
 
                $row = $dbw->selectRow(
                        array( 'revision', 'page' ),
@@ -1382,7 +1365,6 @@ class WikiPage implements Page, IDBAccessObject {
 
                if ( $row ) {
                        if ( wfTimestamp( TS_MW, $row->rev_timestamp ) >= $revision->getTimestamp() ) {
-                               wfProfileOut( __METHOD__ );
                                return false;
                        }
                        $prev = $row->rev_id;
@@ -1395,7 +1377,6 @@ class WikiPage implements Page, IDBAccessObject {
 
                $ret = $this->updateRevisionOn( $dbw, $revision, $prev, $lastRevIsRedirect );
 
-               wfProfileOut( __METHOD__ );
                return $ret;
        }
 
@@ -1514,7 +1495,6 @@ class WikiPage implements Page, IDBAccessObject {
         */
        public function replaceSectionContent( $sectionId, Content $sectionContent, $sectionTitle = '',
                $edittime = null ) {
-               wfProfileIn( __METHOD__ );
 
                $baseRevId = null;
                if ( $edittime && $sectionId !== 'new' ) {
@@ -1525,7 +1505,6 @@ class WikiPage implements Page, IDBAccessObject {
                        }
                }
 
-               wfProfileOut( __METHOD__ );
                return $this->replaceSectionAtRev( $sectionId, $sectionContent, $sectionTitle, $baseRevId );
        }
 
@@ -1545,14 +1524,12 @@ class WikiPage implements Page, IDBAccessObject {
        public function replaceSectionAtRev( $sectionId, Content $sectionContent,
                $sectionTitle = '', $baseRevId = null
        ) {
-               wfProfileIn( __METHOD__ );
 
                if ( strval( $sectionId ) === '' ) {
                        // Whole-page edit; let the whole text through
                        $newContent = $sectionContent;
                } else {
                        if ( !$this->supportsSections() ) {
-                               wfProfileOut( __METHOD__ );
                                throw new MWException( "sections not supported for content model " .
                                        $this->getContentHandler()->getModelID() );
                        }
@@ -1568,7 +1545,6 @@ class WikiPage implements Page, IDBAccessObject {
                                if ( !$rev ) {
                                        wfDebug( __METHOD__ . " asked for bogus section (page: " .
                                                $this->getId() . "; section: $sectionId)\n" );
-                                       wfProfileOut( __METHOD__ );
                                        return null;
                                }
 
@@ -1577,14 +1553,12 @@ class WikiPage implements Page, IDBAccessObject {
 
                        if ( !$oldContent ) {
                                wfDebug( __METHOD__ . ": no page text\n" );
-                               wfProfileOut( __METHOD__ );
                                return null;
                        }
 
                        $newContent = $oldContent->replaceSection( $sectionId, $sectionContent, $sectionTitle );
                }
 
-               wfProfileOut( __METHOD__ );
                return $newContent;
        }
 
@@ -1726,10 +1700,7 @@ class WikiPage implements Page, IDBAccessObject {
                        throw new MWException( 'Something is trying to edit an article with an empty title' );
                }
 
-               wfProfileIn( __METHOD__ );
-
                if ( !$content->getContentHandler()->canBeUsedOn( $this->getTitle() ) ) {
-                       wfProfileOut( __METHOD__ );
                        return Status::newFatal( 'content-not-allowed-here',
                                ContentHandler::getLocalizedName( $content->getModel() ),
                                $this->getTitle()->getPrefixedText() );
@@ -1758,7 +1729,6 @@ class WikiPage implements Page, IDBAccessObject {
                                $status->fatal( 'edit-hook-aborted' );
                        }
 
-                       wfProfileOut( __METHOD__ );
                        return $status;
                }
 
@@ -1805,11 +1775,9 @@ class WikiPage implements Page, IDBAccessObject {
                                wfDebug( __METHOD__ . ": EDIT_UPDATE specified but article doesn't exist\n" );
                                $status->fatal( 'edit-gone-missing' );
 
-                               wfProfileOut( __METHOD__ );
                                return $status;
                        } elseif ( !$old_content ) {
                                // Sanity check for bug 37225
-                               wfProfileOut( __METHOD__ );
                                throw new MWException( "Could not find text for current revision {$oldid}." );
                        }
 
@@ -1840,7 +1808,6 @@ class WikiPage implements Page, IDBAccessObject {
                                        if ( !$status->isOK() ) {
                                                $dbw->rollback( __METHOD__ );
 
-                                               wfProfileOut( __METHOD__ );
                                                return $status;
                                        }
                                        $revisionId = $revision->insertOn( $dbw );
@@ -1856,7 +1823,6 @@ class WikiPage implements Page, IDBAccessObject {
 
                                                $dbw->rollback( __METHOD__ );
 
-                                               wfProfileOut( __METHOD__ );
                                                return $status;
                                        }
 
@@ -1878,7 +1844,7 @@ class WikiPage implements Page, IDBAccessObject {
                                                }
                                        }
                                        $user->incEditCount();
-                               } catch ( MWException $e ) {
+                               } catch ( Exception $e ) {
                                        $dbw->rollback( __METHOD__ );
                                        // Question: Would it perhaps be better if this method turned all
                                        // exceptions into $status's?
@@ -1921,7 +1887,6 @@ class WikiPage implements Page, IDBAccessObject {
                                if ( !$status->isOK() ) {
                                        $dbw->rollback( __METHOD__ );
 
-                                       wfProfileOut( __METHOD__ );
                                        return $status;
                                }
 
@@ -1935,7 +1900,6 @@ class WikiPage implements Page, IDBAccessObject {
                                        $dbw->rollback( __METHOD__ );
                                        $status->fatal( 'edit-already-exists' );
 
-                                       wfProfileOut( __METHOD__ );
                                        return $status;
                                }
 
@@ -1983,7 +1947,7 @@ class WikiPage implements Page, IDBAccessObject {
                                }
                                $user->incEditCount();
 
-                       } catch ( MWException $e ) {
+                       } catch ( Exception $e ) {
                                $dbw->rollback( __METHOD__ );
                                throw $e;
                        }
@@ -2018,7 +1982,6 @@ class WikiPage implements Page, IDBAccessObject {
                        $user->addAutopromoteOnceGroups( 'onEdit' );
                } );
 
-               wfProfileOut( __METHOD__ );
                return $status;
        }
 
@@ -2066,7 +2029,8 @@ class WikiPage implements Page, IDBAccessObject {
         * Returns a stdClass with source, pst and output members
         *
         * @param Content $content
-        * @param int|null $revid
+        * @param Revision|int|null $revision Revision object. For backwards compatibility, a
+        *        revision ID is also accepted, but this is deprecated.
         * @param User|null $user
         * @param string|null $serialFormat
         * @param bool $useCache Check shared prepared edit cache
@@ -2076,9 +2040,22 @@ class WikiPage implements Page, IDBAccessObject {
         * @since 1.21
         */
        public function prepareContentForEdit(
-               Content $content, $revid = null, User $user = null, $serialFormat = null, $useCache = true
+               Content $content, $revision = null, User $user = null, $serialFormat = null, $useCache = true
        ) {
-               global $wgContLang, $wgUser;
+               global $wgContLang, $wgUser, $wgAjaxEditStash;
+
+               if ( is_object( $revision ) ) {
+                       $revid = $revision->getId();
+               } else {
+                       $revid = $revision;
+                       // This code path is deprecated, and nothing is known to
+                       // use it, so performance here shouldn't be a worry.
+                       if ( $revid !== null ) {
+                               $revision = Revision::newFromId( $revid, Revision::READ_LATEST );
+                       } else {
+                               $revision = null;
+                       }
+               }
 
                $user = is_null( $user ) ? $wgUser : $user;
                //XXX: check $user->getId() here???
@@ -2100,7 +2077,7 @@ class WikiPage implements Page, IDBAccessObject {
                }
 
                // The edit may have already been prepared via api.php?action=stashedit
-               $cachedEdit = $useCache
+               $cachedEdit = $useCache && $wgAjaxEditStash
                        ? ApiStashEdit::checkCache( $this->getTitle(), $content, $user )
                        : false;
 
@@ -2129,6 +2106,25 @@ class WikiPage implements Page, IDBAccessObject {
                if ( $cachedEdit ) {
                        $edit->output = $cachedEdit->output;
                } else {
+                       if ( $revision ) {
+                               // We get here if vary-revision is set. This means that this page references
+                               // itself (such as via self-transclusion). In this case, we need to make sure
+                               // that any such self-references refer to the newly-saved revision, and not
+                               // to the previous one, which could otherwise happen due to slave lag.
+                               $oldCallback = $edit->popts->setCurrentRevisionCallback(
+                                       function ( $title, $parser = false ) use ( $revision, &$oldCallback ) {
+                                               if ( $title->equals( $revision->getTitle() ) ) {
+                                                       return $revision;
+                                               } else {
+                                                       return call_user_func(
+                                                               $oldCallback,
+                                                               $title,
+                                                               $parser
+                                                       );
+                                               }
+                                       }
+                               );
+                       }
                        $edit->output = $edit->pstContent
                                ? $edit->pstContent->getParserOutput( $this->mTitle, $revid, $edit->popts )
                                : null;
@@ -2166,8 +2162,6 @@ class WikiPage implements Page, IDBAccessObject {
        public function doEditUpdates( Revision $revision, User $user, array $options = array() ) {
                global $wgEnableParserCache;
 
-               wfProfileIn( __METHOD__ );
-
                $options += array(
                        'changed' => true,
                        'created' => false,
@@ -2181,7 +2175,7 @@ class WikiPage implements Page, IDBAccessObject {
                // already pre-save transformed once.
                if ( !$this->mPreparedEdit || $this->mPreparedEdit->output->getFlag( 'vary-revision' ) ) {
                        wfDebug( __METHOD__ . ": No prepared edit or vary-revision is set...\n" );
-                       $editInfo = $this->prepareContentForEdit( $content, $revision->getId(), $user );
+                       $editInfo = $this->prepareContentForEdit( $content, $revision, $user );
                } else {
                        wfDebug( __METHOD__ . ": No vary-revision, using prepared edit...\n" );
                        $editInfo = $this->mPreparedEdit;
@@ -2206,15 +2200,11 @@ class WikiPage implements Page, IDBAccessObject {
                Hooks::run( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
 
                if ( Hooks::run( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
-                       if ( 0 == mt_rand( 0, 99 ) ) {
-                               // Flush old entries from the `recentchanges` table; we do this on
-                               // random requests so as to avoid an increase in writes for no good reason
-                               RecentChange::purgeExpiredChanges();
-                       }
+                       // Flush old entries from the `recentchanges` table
+                       JobQueueGroup::singleton()->push( RecentChangesUpdateJob::newPurgeJob() );
                }
 
                if ( !$this->exists() ) {
-                       wfProfileOut( __METHOD__ );
                        return;
                }
 
@@ -2279,7 +2269,6 @@ class WikiPage implements Page, IDBAccessObject {
                        self::onArticleEdit( $this->mTitle );
                }
 
-               wfProfileOut( __METHOD__ );
        }
 
        /**
@@ -2315,7 +2304,6 @@ class WikiPage implements Page, IDBAccessObject {
        public function doQuickEditContent( Content $content, User $user, $comment = '', $minor = false,
                $serialFormat = null
        ) {
-               wfProfileIn( __METHOD__ );
 
                $serialized = $content->serialize( $serialFormat );
 
@@ -2335,7 +2323,6 @@ class WikiPage implements Page, IDBAccessObject {
 
                Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
 
-               wfProfileOut( __METHOD__ );
        }
 
        /**
@@ -3026,8 +3013,8 @@ class WikiPage implements Page, IDBAccessObject {
 
                // Get the last edit not by this guy...
                // Note: these may not be public values
-               $user = intval( $current->getRawUser() );
-               $user_text = $dbw->addQuotes( $current->getRawUserText() );
+               $user = intval( $current->getUser( Revision::RAW ) );
+               $user_text = $dbw->addQuotes( $current->getUserText( Revision::RAW ) );
                $s = $dbw->selectRow( 'revision',
                        array( 'rev_id', 'rev_timestamp', 'rev_deleted' ),
                        array( 'rev_page' => $current->getPage(),