X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Flibs%2Frdbms%2Flbfactory%2FLBFactory.php;h=5501e6a9ca6df079889f3f0f43618e734221aa39;hb=52af356cad3799ebec3826e1e4743d76a114da3e;hp=ccaebd3cd42b9eecf58af7ccd5172d09610e33eb;hpb=42f201ebe78d1aba18176f8b3cef5cf733c018a8;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/libs/rdbms/lbfactory/LBFactory.php b/includes/libs/rdbms/lbfactory/LBFactory.php index ccaebd3cd4..5501e6a9ca 100644 --- a/includes/libs/rdbms/lbfactory/LBFactory.php +++ b/includes/libs/rdbms/lbfactory/LBFactory.php @@ -95,6 +95,8 @@ abstract class LBFactory implements ILBFactory { const ROUND_BEGINNING = 'within-begin'; const ROUND_COMMITTING = 'within-commit'; const ROUND_ROLLING_BACK = 'within-rollback'; + const ROUND_COMMIT_CALLBACKS = 'within-commit-callbacks'; + const ROUND_ROLLBACK_CALLBACKS = 'within-rollback-callbacks'; private static $loggerFields = [ 'replLogger', 'connLogger', 'queryLogger', 'perfLogger' ]; @@ -216,7 +218,8 @@ abstract class LBFactory implements ILBFactory { final public function commitAll( $fname = __METHOD__, array $options = [] ) { $this->commitMasterChanges( $fname, $options ); - $this->forEachLBCallMethod( 'commitAll', [ $fname ] ); + $this->forEachLBCallMethod( 'flushMasterSnapshots', [ $fname ] ); + $this->forEachLBCallMethod( 'flushReplicaSnapshots', [ $fname ] ); } final public function beginMasterChanges( $fname = __METHOD__ ) { @@ -246,7 +249,12 @@ abstract class LBFactory implements ILBFactory { /** @noinspection PhpUnusedLocalVariableInspection */ $scope = $this->getScopedPHPBehaviorForCommit(); // try to ignore client aborts // Run pre-commit callbacks and suppress post-commit callbacks, aborting on failure - $this->forEachLBCallMethod( 'finalizeMasterChanges' ); + do { + $count = 0; // number of callbacks executed this iteration + $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$count ) { + $count += $lb->finalizeMasterChanges(); + } ); + } while ( $count > 0 ); $this->trxRoundId = false; // Perform pre-commit checks, aborting on failure $this->forEachLBCallMethod( 'approveMasterChanges', [ $options ] ); @@ -254,6 +262,31 @@ abstract class LBFactory implements ILBFactory { $this->logIfMultiDbTransaction(); // Actually perform the commit on all master DB connections and revert DBO_TRX $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] ); + // Run all post-commit callbacks in a separate step + $this->trxRoundStage = self::ROUND_COMMIT_CALLBACKS; + $e = $this->executePostTransactionCallbacks(); + $this->trxRoundStage = self::ROUND_CURSORY; + // Throw any last post-commit callback error + if ( $e instanceof Exception ) { + throw $e; + } + } + + final public function rollbackMasterChanges( $fname = __METHOD__ ) { + $this->trxRoundStage = self::ROUND_ROLLING_BACK; + $this->trxRoundId = false; + // Actually perform the rollback on all master DB connections and revert DBO_TRX + $this->forEachLBCallMethod( 'rollbackMasterChanges', [ $fname ] ); + // Run all post-commit callbacks in a separate step + $this->trxRoundStage = self::ROUND_ROLLBACK_CALLBACKS; + $this->executePostTransactionCallbacks(); + $this->trxRoundStage = self::ROUND_CURSORY; + } + + /** + * @return Exception|null + */ + private function executePostTransactionCallbacks() { // Run all post-commit callbacks until new ones stop getting added $e = null; // first callback exception do { @@ -267,20 +300,8 @@ abstract class LBFactory implements ILBFactory { $ex = $lb->runMasterTransactionListenerCallbacks(); $e = $e ?: $ex; } ); - $this->trxRoundStage = self::ROUND_CURSORY; - // Throw any last post-commit callback error - if ( $e instanceof Exception ) { - throw $e; - } - } - final public function rollbackMasterChanges( $fname = __METHOD__ ) { - $this->trxRoundStage = self::ROUND_ROLLING_BACK; - $this->trxRoundId = false; - $this->forEachLBCallMethod( 'rollbackMasterChanges', [ $fname ] ); - $this->forEachLBCallMethod( 'runMasterTransactionIdleCallbacks' ); - $this->forEachLBCallMethod( 'runMasterTransactionListenerCallbacks' ); - $this->trxRoundStage = self::ROUND_CURSORY; + return $e; } public function hasTransactionRound() { @@ -534,6 +555,14 @@ abstract class LBFactory implements ILBFactory { * @return array */ final protected function baseLoadBalancerParams() { + if ( $this->trxRoundStage === self::ROUND_COMMIT_CALLBACKS ) { + $initStage = ILoadBalancer::STAGE_POSTCOMMIT_CALLBACKS; + } elseif ( $this->trxRoundStage === self::ROUND_ROLLBACK_CALLBACKS ) { + $initStage = ILoadBalancer::STAGE_POSTROLLBACK_CALLBACKS; + } else { + $initStage = null; + } + return [ 'localDomain' => $this->localDomain, 'readOnlyReason' => $this->readOnlyReason, @@ -553,7 +582,8 @@ abstract class LBFactory implements ILBFactory { // Defer ChronologyProtector construction in case setRequestInfo() ends up // being called later (but before the first connection attempt) (T192611) $this->getChronologyProtector()->initLB( $lb ); - } + }, + 'roundStage' => $initStage ]; } @@ -610,6 +640,36 @@ abstract class LBFactory implements ILBFactory { return strpos( $url, '?' ) === false ? "$url?cpPosIndex=$index" : "$url&cpPosIndex=$index"; } + /** + * @param int $index Write index + * @param int $time UNIX timestamp + * @return string Timestamp-qualified write index of the form "." + * @since 1.32 + */ + public static function makeCookieValueFromCPIndex( $index, $time ) { + return $index . '@' . $time; + } + + /** + * @param string $value String possibly of the form "" or "@" + * @param int $minTimestamp Lowest UNIX timestamp of non-expired values (if present) + * @return int|null Write index or null if $value is empty or expired + * @since 1.32 + */ + public static function getCPIndexFromCookieValue( $value, $minTimestamp ) { + if ( !preg_match( '/^(\d+)(?:@(\d+))?$/', $value, $m ) ) { + return null; + } + + $index = (int)$m[1]; + + if ( isset( $m[2] ) && $m[2] !== '' && (int)$m[2] < $minTimestamp ) { + return null; // expired + } + + return ( $index > 0 ) ? $index : null; + } + public function setRequestInfo( array $info ) { if ( $this->chronProt ) { throw new LogicException( 'ChronologyProtector already initialized.' );