X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FWikiPage.php;h=9dc9c2c84808e94b4498f92bc42fdd88ee0ce3c4;hb=4bdad0e395eee536abf71fb180d4e5cf58df171a;hp=670b36ea983b4ebc35918a8f58fb49d8f188f659;hpb=c5d3a6a715514b895caf301d957cfa351c8e49ca;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/WikiPage.php b/includes/WikiPage.php index 670b36ea98..9dc9c2c848 100644 --- a/includes/WikiPage.php +++ b/includes/WikiPage.php @@ -33,29 +33,9 @@ abstract class Page {} * * @internal documentation reviewed 15 Mar 2010 */ -class WikiPage extends Page { +class WikiPage extends Page implements IDBAccessObject { // Constants for $mDataLoadedFrom and related - /** - * Data has not been loaded yet (or the object was cleared) - */ - const DATA_NOT_LOADED = 0; - - /** - * Data has been loaded from a slave database - */ - const DATA_FROM_SLAVE = 1; - - /** - * Data has been loaded from the master database - */ - const DATA_FROM_MASTER = 2; - - /** - * Data has been loaded from the master database using FOR UPDATE - */ - const DATA_FOR_UPDATE = 3; - /** * @var Title */ @@ -71,9 +51,9 @@ class WikiPage extends Page { /**@}}*/ /** - * @var int; one of the DATA_* constants + * @var int; one of the READ_* constants */ - protected $mDataLoadedFrom = self::DATA_NOT_LOADED; + protected $mDataLoadedFrom = self::READ_NONE; /** * @var Title @@ -142,14 +122,14 @@ class WikiPage extends Page { * * @param $id Int article ID to load * @param $from string|int one of the following values: - * - "fromdb" or self::DATA_FROM_SLAVE to select from a slave database - * - "fromdbmaster" or self::DATA_FROM_MASTER to select from the master database + * - "fromdb" or WikiPage::READ_NORMAL to select from a slave database + * - "fromdbmaster" or WikiPage::READ_LATEST to select from the master database * * @return WikiPage|null */ public static function newFromID( $id, $from = 'fromdb' ) { $from = self::convertSelectType( $from ); - $db = wfGetDB( $from === self::DATA_FROM_MASTER ? DB_MASTER : DB_SLAVE ); + $db = wfGetDB( $from === self::READ_LATEST ? DB_MASTER : DB_SLAVE ); $row = $db->selectRow( 'page', self::selectFields(), array( 'page_id' => $id ), __METHOD__ ); if ( !$row ) { return null; @@ -164,9 +144,9 @@ class WikiPage extends Page { * @param $row object: database row containing at least fields returned * by selectFields(). * @param $from string|int: source of $data: - * - "fromdb" or self::DATA_FROM_SLAVE: from a slave DB - * - "fromdbmaster" or self::DATA_FROM_MASTER: from the master DB - * - "forupdate" or self::DATA_FOR_UPDATE: from the master DB using SELECT FOR UPDATE + * - "fromdb" or WikiPage::READ_NORMAL: from a slave DB + * - "fromdbmaster" or WikiPage::READ_LATEST: from the master DB + * - "forupdate" or WikiPage::READ_LOCKING: from the master DB using SELECT FOR UPDATE * @return WikiPage */ public static function newFromRow( $row, $from = 'fromdb' ) { @@ -176,7 +156,7 @@ class WikiPage extends Page { } /** - * Convert 'fromdb', 'fromdbmaster' and 'forupdate' to DATA_* constants. + * Convert 'fromdb', 'fromdbmaster' and 'forupdate' to READ_* constants. * * @param $type object|string|int * @return mixed @@ -184,11 +164,11 @@ class WikiPage extends Page { private static function convertSelectType( $type ) { switch ( $type ) { case 'fromdb': - return self::DATA_FROM_SLAVE; + return self::READ_NORMAL; case 'fromdbmaster': - return self::DATA_FROM_MASTER; + return self::READ_LATEST; case 'forupdate': - return self::DATA_FOR_UPDATE; + return self::READ_LOCKING; default: // It may already be an integer or whatever else return $type; @@ -223,7 +203,7 @@ class WikiPage extends Page { */ public function clear() { $this->mDataLoaded = false; - $this->mDataLoadedFrom = self::DATA_NOT_LOADED; + $this->mDataLoadedFrom = self::READ_NONE; $this->clearCacheFields(); } @@ -317,9 +297,9 @@ class WikiPage extends Page { * * @param $from object|string|int One of the following: * - A DB query result object - * - "fromdb" or self::DATA_FROM_SLAVE to get from a slave DB - * - "fromdbmaster" or self::DATA_FROM_MASTER to get from the master DB - * - "forupdate" or self::DATA_FOR_UPDATE to get from the master DB using SELECT FOR UPDATE + * - "fromdb" or WikiPage::READ_NORMAL to get from a slave DB + * - "fromdbmaster" or WikiPage::READ_LATEST to get from the master DB + * - "forupdate" or WikiPage::READ_LOCKING to get from the master DB using SELECT FOR UPDATE * * @return void */ @@ -330,25 +310,25 @@ class WikiPage extends Page { return; } - if ( $from === self::DATA_FOR_UPDATE ) { + if ( $from === self::READ_LOCKING ) { $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle, array( 'FOR UPDATE' ) ); - } elseif ( $from === self::DATA_FROM_MASTER ) { + } elseif ( $from === self::READ_LATEST ) { $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); - } elseif ( $from === self::DATA_FROM_SLAVE ) { + } elseif ( $from === self::READ_NORMAL ) { $data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle ); # Use a "last rev inserted" timestamp key to dimish 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::DATA_FROM_MASTER; + $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. $data = $from; - $from = self::DATA_FROM_SLAVE; + $from = self::READ_NORMAL; } $this->loadFromRow( $data, $from ); @@ -361,9 +341,9 @@ class WikiPage extends Page { * @param $data object: database row containing at least fields returned * by selectFields() * @param $from string|int One of the following: - * - "fromdb" or self::DATA_FROM_SLAVE if the data comes from a slave DB - * - "fromdbmaster" or self::DATA_FROM_MASTER if the data comes from the master DB - * - "forupdate" or self::DATA_FOR_UPDATE if the data comes from from + * - "fromdb" or WikiPage::READ_NORMAL if the data comes from a slave DB + * - "fromdbmaster" or WikiPage::READ_LATEST if the data comes from the master DB + * - "forupdate" or WikiPage::READ_LOCKING if the data comes from from * the master DB using SELECT FOR UPDATE */ public function loadFromRow( $data, $from ) { @@ -540,7 +520,14 @@ class WikiPage extends Page { return; // page doesn't exist or is missing page_latest info } - $revision = Revision::newFromPageId( $this->getId(), $latest ); + // 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; + $revision = Revision::newFromPageId( $this->getId(), $latest, $flags ); if ( $revision ) { // sanity $this->setLastEdit( $revision ); } @@ -1181,7 +1168,7 @@ class WikiPage extends Page { $conditions, __METHOD__ ); - $result = $dbw->affectedRows() != 0; + $result = $dbw->affectedRows() > 0; if ( $result ) { $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect ); $this->setLastEdit( $revision ); @@ -1421,7 +1408,7 @@ class WikiPage extends Page { * Compatibility note: this function previously returned a boolean value indicating success/failure */ public function doEdit( $text, $summary, $flags = 0, $baseRevId = false, $user = null ) { - global $wgUser, $wgUseAutomaticEditSummaries; + global $wgUser, $wgUseAutomaticEditSummaries, $wgUseRCPatrol, $wgUseNPPatrol; # Low-level sanity check if ( $this->mTitle->getText() === '' ) { @@ -1487,6 +1474,10 @@ class WikiPage extends Page { wfProfileOut( __METHOD__ ); return $status; + } elseif ( $oldtext === false ) { + # Sanity check for bug 37225 + wfProfileOut( __METHOD__ ); + throw new MWException( "Could not find text for current revision {$oldid}." ); } $revision = new Revision( array( @@ -1519,45 +1510,40 @@ class WikiPage extends Page { $ok = $this->updateRevisionOn( $dbw, $revision, $oldid, $oldIsRedirect ); if ( !$ok ) { - /* Belated edit conflict! Run away!! */ + # Belated edit conflict! Run away!! $status->fatal( 'edit-conflict' ); - $revisionId = 0; $dbw->rollback( __METHOD__ ); - } else { - global $wgUseRCPatrol; - wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) ); - # Update recentchanges - if ( !( $flags & EDIT_SUPPRESS_RC ) ) { - # Mark as patrolled if the user can do so - $patrolled = $wgUseRCPatrol && !count( - $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) ); - # Add RC row to the DB - $rc = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $user, $summary, - $oldid, $this->getTimestamp(), $bot, '', $oldsize, $newsize, - $revisionId, $patrolled - ); - - # Log auto-patrolled edits - if ( $patrolled ) { - PatrolLog::record( $rc, true, $user ); - } + + wfProfileOut( __METHOD__ ); + return $status; + } + + wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) ); + # Update recentchanges + if ( !( $flags & EDIT_SUPPRESS_RC ) ) { + # Mark as patrolled if the user can do so + $patrolled = $wgUseRCPatrol && !count( + $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) ); + # Add RC row to the DB + $rc = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $user, $summary, + $oldid, $this->getTimestamp(), $bot, '', $oldsize, $newsize, + $revisionId, $patrolled + ); + + # Log auto-patrolled edits + if ( $patrolled ) { + PatrolLog::record( $rc, true, $user ); } - $user->incEditCount(); - $dbw->commit( __METHOD__ ); } + $user->incEditCount(); + $dbw->commit( __METHOD__ ); } else { // Bug 32948: revision ID must be set to page {{REVISIONID}} and // related variables correctly $revision->setId( $this->getLatest() ); } - // Now that ignore_user_abort is restored, we can respond to fatal errors - if ( !$status->isOK() ) { - wfProfileOut( __METHOD__ ); - return $status; - } - # Update links tables, site stats, etc. $this->doEditUpdates( $revision, $user, array( 'changed' => $changed, 'oldcountable' => $oldcountable ) ); @@ -1609,8 +1595,6 @@ class WikiPage extends Page { # Update recentchanges if ( !( $flags & EDIT_SUPPRESS_RC ) ) { - global $wgUseRCPatrol, $wgUseNPPatrol; - # Mark as patrolled if the user can do so $patrolled = ( $wgUseRCPatrol || $wgUseNPPatrol ) && !count( $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) ); @@ -1804,9 +1788,9 @@ class WikiPage extends Page { wfDebug( __METHOD__ . ": invalid username\n" ); } elseif ( User::isIP( $shortTitle ) ) { // An anonymous user - $other->setNewtalk( true ); + $other->setNewtalk( true, $revision ); } elseif ( $other->isLoggedIn() ) { - $other->setNewtalk( true ); + $other->setNewtalk( true, $revision ); } else { wfDebug( __METHOD__ . ": don't need to notify a nonexistent user\n" ); } @@ -2602,7 +2586,7 @@ class WikiPage extends Page { if ( is_object( $rt ) && ( !is_object( $ot ) || !$rt->equals( $ot ) || $ot->getFragment() != $rt->getFragment() ) ) { $truncatedtext = $wgContLang->truncate( str_replace( "\n", ' ', $newtext ), - max( 0, 250 + max( 0, 255 - strlen( wfMsgForContent( 'autoredircomment' ) ) - strlen( $rt->getFullText() ) ) );