MediaWiki master
DeferredUpdatesScopeMediaWikiStack.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Deferred;
22
25
37
38 private function areDatabaseTransactionsActive(): bool {
39 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
40 if ( $lbFactory->hasTransactionRound()
41 || !$lbFactory->isReadyForRoundOperations()
42 ) {
43 return true;
44 }
45
46 foreach ( $lbFactory->getAllLBs() as $lb ) {
47 if ( $lb->hasPrimaryChanges() || $lb->explicitTrxActive() ) {
48 return true;
49 }
50 }
51
52 return false;
53 }
54
55 public function allowOpportunisticUpdates(): bool {
56 if ( MW_ENTRY_POINT !== 'cli' ) {
57 // In web req
58 return false;
59 }
60
61 // Run the updates only if they will have outer transaction scope
62 if ( $this->areDatabaseTransactionsActive() ) {
63 // transaction round is active or connection is not ready for commit()
64 return false;
65 }
66
67 return true;
68 }
69
70 public function queueDataUpdate( EnqueueableDataUpdate $update ): void {
71 $spec = $update->getAsJobSpecification();
72 $jobQueueGroupFactory = MediaWikiServices::getInstance()->getJobQueueGroupFactory();
73 $jobQueueGroupFactory->makeJobQueueGroup( $spec['domain'] )->push( $spec['job'] );
74 }
75
76 public function onRunUpdateStart( DeferrableUpdate $update ): void {
77 // Increment a counter metric
78 $type = get_class( $update )
79 . ( $update instanceof DeferrableCallback ? '_' . $update->getOrigin() : '' );
80 $httpMethod = MW_ENTRY_POINT === 'cli' ? 'cli' : strtolower( $_SERVER['REQUEST_METHOD'] ?? 'GET' );
81 $stats = MediaWikiServices::getInstance()->getStatsFactory();
82 $stats->getCounter( 'deferred_updates_total' )
83 ->setLabel( 'http_method', $httpMethod )
84 ->setLabel( 'type', $type )
85 ->copyToStatsdAt( "deferred_updates.$httpMethod.$type" )
86 ->increment();
87
88 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
89 $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
90 if ( !$ticket || $lbFactory->hasTransactionRound() ) {
91 throw new DBTransactionError( null, "A database transaction round is pending." );
92 }
93
94 if ( $update instanceof DataUpdate ) {
95 $update->setTransactionTicket( $ticket );
96 }
97
98 // Designate $update::doUpdate() as the write round owner
99 $fnameTrxOwner = ( $update instanceof DeferrableCallback )
100 ? $update->getOrigin()
101 : get_class( $update ) . '::doUpdate';
102
103 // Determine whether the write round will be explicit or implicit
104 $useExplicitTrxRound = !(
105 $update instanceof TransactionRoundAwareUpdate &&
106 $update->getTransactionRoundRequirement() == $update::TRX_ROUND_ABSENT
107 );
108
109 // Ensure any stale repeatable-read snapshot on the primary DB have been flushed
110 // before running the update. E.g. left-over from an implicit transaction round
111 if ( $useExplicitTrxRound ) {
112 // new explicit round
113 $lbFactory->beginPrimaryChanges( $fnameTrxOwner );
114 } else {
115 // new implicit round
116 $lbFactory->commitPrimaryChanges( $fnameTrxOwner );
117 }
118 }
119
120 public function onRunUpdateEnd( DeferrableUpdate $update ): void {
121 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
122
123 $fnameTrxOwner = ( $update instanceof DeferrableCallback )
124 ? $update->getOrigin()
125 : get_class( $update ) . '::doUpdate';
126
127 // Commit any pending changes from the explicit or implicit transaction round
128 $lbFactory->commitPrimaryChanges( $fnameTrxOwner );
129 }
130
131 public function onRunUpdateFailed( DeferrableUpdate $update ): void {
132 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
133 $lbFactory->rollbackPrimaryChanges( __METHOD__ );
134 }
135}
136
138class_alias( DeferredUpdatesScopeMediaWikiStack::class, 'DeferredUpdatesScopeMediaWikiStack' );
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
const MW_ENTRY_POINT
Definition api.php:35
Abstract base class for update jobs that do something with some secondary data extracted from article...
This class decouples DeferredUpdates's awareness of MediaWikiServices to ease unit testing.
allowOpportunisticUpdates()
Whether DeferredUpdates::addUpdate() may run the update right away.
queueDataUpdate(EnqueueableDataUpdate $update)
Queue an EnqueueableDataUpdate as a job instead.
DeferredUpdates helper class for tracking DeferrableUpdate::doUpdate() nesting levels caused by neste...
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Callback wrapper that has an originating method.
Interface that deferrable updates should implement.
Interface that marks a DataUpdate as enqueuable via the JobQueue.