getDBLoadBalancerFactory(); if ( $lbFactory->hasTransactionRound() || !$lbFactory->isReadyForRoundOperations() ) { return true; } foreach ( $lbFactory->getAllLBs() as $lb ) { if ( $lb->hasPrimaryChanges() || $lb->explicitTrxActive() ) { return true; } } return false; } public function allowOpportunisticUpdates(): bool { if ( MW_ENTRY_POINT !== 'cli' ) { // In web req return false; } // Run the updates only if they will have outer transaction scope if ( $this->areDatabaseTransactionsActive() ) { // transaction round is active or connection is not ready for commit() return false; } return true; } public function queueDataUpdate( EnqueueableDataUpdate $update ): void { $spec = $update->getAsJobSpecification(); $jobQueueGroupFactory = MediaWikiServices::getInstance()->getJobQueueGroupFactory(); $jobQueueGroupFactory->makeJobQueueGroup( $spec['domain'] )->push( $spec['job'] ); } public function onRunUpdateStart( DeferrableUpdate $update ): void { // Increment a counter metric $type = get_class( $update ) . ( $update instanceof DeferrableCallback ? '_' . $update->getOrigin() : '' ); $httpMethod = MW_ENTRY_POINT === 'cli' ? 'cli' : strtolower( $_SERVER['REQUEST_METHOD'] ?? 'GET' ); $stats = MediaWikiServices::getInstance()->getStatsFactory(); $stats->getCounter( 'deferred_updates_total' ) ->setLabel( 'http_method', $httpMethod ) ->setLabel( 'type', $type ) ->copyToStatsdAt( "deferred_updates.$httpMethod.$type" ) ->increment(); $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ ); if ( !$ticket || $lbFactory->hasTransactionRound() ) { throw new DBTransactionError( null, "A database transaction round is pending." ); } if ( $update instanceof DataUpdate ) { $update->setTransactionTicket( $ticket ); } // Designate $update::doUpdate() as the write round owner $fnameTrxOwner = ( $update instanceof DeferrableCallback ) ? $update->getOrigin() : get_class( $update ) . '::doUpdate'; // Determine whether the write round will be explicit or implicit $useExplicitTrxRound = !( $update instanceof TransactionRoundAwareUpdate && $update->getTransactionRoundRequirement() == $update::TRX_ROUND_ABSENT ); // Ensure any stale repeatable-read snapshot on the primary DB have been flushed // before running the update. E.g. left-over from an implicit transaction round if ( $useExplicitTrxRound ) { // new explicit round $lbFactory->beginPrimaryChanges( $fnameTrxOwner ); } else { // new implicit round $lbFactory->commitPrimaryChanges( $fnameTrxOwner ); } } public function onRunUpdateEnd( DeferrableUpdate $update ): void { $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); $fnameTrxOwner = ( $update instanceof DeferrableCallback ) ? $update->getOrigin() : get_class( $update ) . '::doUpdate'; // Commit any pending changes from the explicit or implicit transaction round $lbFactory->commitPrimaryChanges( $fnameTrxOwner ); } public function onRunUpdateFailed( DeferrableUpdate $update ): void { $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); $lbFactory->rollbackPrimaryChanges( __METHOD__ ); } } /** @deprecated class alias since 1.42 */ class_alias( DeferredUpdatesScopeMediaWikiStack::class, 'DeferredUpdatesScopeMediaWikiStack' );