X-Git-Url: http://git.cyclocoop.org/%22%20.%20generer_url_ecrire%28%22suivi_revisions%22%29%20.%20%22?a=blobdiff_plain;f=includes%2Fpage%2FWikiPage.php;h=5caffaba14f639d0d178011d142c4a7fa72f6af9;hb=5bfbff2670f0011b194fb10b7195c0a1778459d2;hp=5527ace2f77abfd32c78367b6b140517d364c798;hpb=4f1067e27efe648e6089ab0b28fac1b2c3481816;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 5527ace2f7..5caffaba14 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -367,14 +367,12 @@ class WikiPage implements Page, IDBAccessObject { $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); } elseif ( $from === self::READ_NORMAL ) { $data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle ); - // Use a "last rev inserted" timestamp key to diminish the issue of slave lag. - // Note that DB also stores the master position in the session and checks it. - $touched = $this->getCachedLastEditTime(); - if ( $touched ) { // key set - if ( !$data || $touched > wfTimestamp( TS_MW, $data->page_touched ) ) { - $from = self::READ_LATEST; - $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); - } + if ( !$data + && wfGetLB()->getServerCount() > 1 + && wfGetLB()->hasOrMadeRecentMasterChanges() + ) { + $from = self::READ_LATEST; + $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); } } else { // No idea from where the caller got this data, assume slave database. @@ -602,13 +600,23 @@ class WikiPage implements Page, IDBAccessObject { return; // page doesn't exist or is missing page_latest info } - // Bug 37225: if session S1 loads the page row FOR UPDATE, the result always includes the - // latest changes committed. This is true even within REPEATABLE-READ transactions, where - // S1 normally only sees changes committed before the first S1 SELECT. Thus we need S1 to - // also gets the revision row FOR UPDATE; otherwise, it may not find it since a page row - // UPDATE and revision row INSERT by S2 may have happened after the first S1 SELECT. - // http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read. - $flags = ( $this->mDataLoadedFrom == self::READ_LOCKING ) ? Revision::READ_LOCKING : 0; + if ( $this->mDataLoadedFrom == self::READ_LOCKING ) { + // Bug 37225: if session S1 loads the page row FOR UPDATE, the result always + // includes the latest changes committed. This is true even within REPEATABLE-READ + // transactions, where S1 normally only sees changes committed before the first S1 + // SELECT. Thus we need S1 to also gets the revision row FOR UPDATE; otherwise, it + // may not find it since a page row UPDATE and revision row INSERT by S2 may have + // happened after the first S1 SELECT. + // http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read. + $flags = Revision::READ_LOCKING; + } elseif ( $this->mDataLoadedFrom == self::READ_LATEST ) { + // Bug T93976: if page_latest was loaded from the master, fetch the + // revision from there as well, as it may not exist yet on a slave DB. + // Also, this keeps the queries in the same REPEATABLE-READ snapshot. + $flags = Revision::READ_LATEST; + } else { + $flags = 0; + } $revision = Revision::newFromPageId( $this->getId(), $latest, $flags ); if ( $revision ) { // sanity $this->setLastEdit( $revision ); @@ -800,29 +808,6 @@ class WikiPage implements Page, IDBAccessObject { } } - /** - * Get the cached timestamp for the last time the page changed. - * This is only used to help handle slave lag by comparing to page_touched. - * @return string MW timestamp - */ - protected function getCachedLastEditTime() { - global $wgMemc; - $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) ); - return $wgMemc->get( $key ); - } - - /** - * Set the cached timestamp for the last time the page changed. - * This is only used to help handle slave lag by comparing to page_touched. - * @param string $timestamp - * @return void - */ - public function setCachedLastEditTime( $timestamp ) { - global $wgMemc; - $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) ); - $wgMemc->set( $key, wfTimestamp( TS_MW, $timestamp ), 60 * 15 ); - } - /** * Determine whether a page would be suitable for being counted as an * article in the site_stats table based on the title & its content @@ -1261,6 +1246,13 @@ class WikiPage implements Page, IDBAccessObject { ) { global $wgContentHandlerUseDB; + // Assertion to try to catch T92046 + if ( (int)$revision->getId() === 0 ) { + throw new InvalidArgumentException( + __METHOD__ . ': Revision has ID ' . var_export( $revision->getId(), 1 ) + ); + } + $content = $revision->getContent(); $len = $content ? $content->getSize() : 0; $rt = $content ? $content->getUltimateRedirectTarget() : null; @@ -1294,7 +1286,6 @@ class WikiPage implements Page, IDBAccessObject { if ( $result ) { $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect ); $this->setLastEdit( $revision ); - $this->setCachedLastEditTime( $now ); $this->mLatest = $revision->getId(); $this->mIsRedirect = (bool)$rt; // Update the LinkCache. @@ -1496,8 +1487,18 @@ class WikiPage implements Page, IDBAccessObject { $baseRevId = null; if ( $edittime && $sectionId !== 'new' ) { - $dbw = wfGetDB( DB_MASTER ); - $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime ); + $dbr = wfGetDB( DB_SLAVE ); + $rev = Revision::loadFromTimestamp( $dbr, $this->mTitle, $edittime ); + // Try the master if this thread may have just added it. + // This could be abstracted into a Revision method, but we don't want + // to encourage loading of revisions by timestamp. + if ( !$rev + && wfGetLB()->getServerCount() > 1 + && wfGetLB()->hasOrMadeRecentMasterChanges() + ) { + $dbw = wfGetDB( DB_MASTER ); + $rev = Revision::loadFromTimestamp( $dbw, $this->mTitle, $edittime ); + } if ( $rev ) { $baseRevId = $rev->getId(); } @@ -1536,10 +1537,7 @@ class WikiPage implements Page, IDBAccessObject { if ( is_null( $baseRevId ) || $sectionId === 'new' ) { $oldContent = $this->getContent(); } else { - // TODO: try DB_SLAVE first - $dbw = wfGetDB( DB_MASTER ); - $rev = Revision::loadFromId( $dbw, $baseRevId ); - + $rev = Revision::newFromId( $baseRevId ); if ( !$rev ) { wfDebug( __METHOD__ . " asked for bogus section (page: " . $this->getId() . "; section: $sectionId)\n" ); @@ -1982,6 +1980,7 @@ class WikiPage implements Page, IDBAccessObject { // Promote user to any groups they meet the criteria for $dbw->onTransactionIdle( function () use ( $user ) { $user->addAutopromoteOnceGroups( 'onEdit' ); + $user->addAutopromoteOnceGroups( 'onView' ); // b/c } ); return $status; @@ -3383,12 +3382,15 @@ class WikiPage implements Page, IDBAccessObject { * Opportunistically enqueue link update jobs given fresh parser output if useful * * @param ParserOutput $parserOutput Current version page output - * @return bool Whether a job was pushed * @since 1.25 */ public function triggerOpportunisticLinksUpdate( ParserOutput $parserOutput ) { if ( wfReadOnly() ) { - return false; + return; + } + + if ( !Hooks::run( 'OpportunisticLinksUpdate', array( $this, $this->mTitle, $parserOutput ) ) ) { + return; } if ( $this->mTitle->areRestrictionsCascading() ) { @@ -3399,7 +3401,7 @@ class WikiPage implements Page, IDBAccessObject { $params = array(); } else { // If the inclusions are deterministic, the edit-triggered link jobs are enough - return false; + return; } // Check if the last link refresh was before page_touched @@ -3407,10 +3409,10 @@ class WikiPage implements Page, IDBAccessObject { JobQueueGroup::singleton()->push( EnqueueJob::newFromLocalJobs( new JobSpecification( 'refreshLinks', $params, array(), $this->mTitle ) ) ); - return true; + return; } - return false; + return; } /**