Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 49 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
DeferredUpdatesScopeMediaWikiStack | |
0.00% |
0 / 48 |
|
0.00% |
0 / 6 |
506 | |
0.00% |
0 / 1 |
areDatabaseTransactionsActive | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
42 | |||
allowOpportunisticUpdates | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
queueDataUpdate | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
onRunUpdateStart | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
90 | |||
onRunUpdateEnd | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
onRunUpdateFailed | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\Deferred; |
22 | |
23 | use MediaWiki\MediaWikiServices; |
24 | use Wikimedia\Rdbms\DBTransactionError; |
25 | |
26 | /** |
27 | * This class decouples DeferredUpdates's awareness of MediaWikiServices to ease unit testing. |
28 | * |
29 | * NOTE: As a process-level utility, it is important that MediaWikiServices::getInstance() is |
30 | * referenced explicitly each time, so as to not cache potentially stale references. |
31 | * For example after the Installer, or MediaWikiIntegrationTestCase, replace the service container. |
32 | * |
33 | * @internal For use by DeferredUpdates only |
34 | * @since 1.41 |
35 | */ |
36 | class DeferredUpdatesScopeMediaWikiStack extends DeferredUpdatesScopeStack { |
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 transaction round owner |
99 | $fnameTrxOwner = ( $update instanceof DeferrableCallback ) |
100 | ? $update->getOrigin() |
101 | : get_class( $update ) . '::doUpdate'; |
102 | |
103 | // Determine whether the transaction round will be explicit or implicit |
104 | $useExplicitTrxRound = !( |
105 | $update instanceof TransactionRoundAwareUpdate && |
106 | $update->getTransactionRoundRequirement() == $update::TRX_ROUND_ABSENT |
107 | ); |
108 | if ( $useExplicitTrxRound ) { |
109 | // Start a new explicit round |
110 | $lbFactory->beginPrimaryChanges( $fnameTrxOwner ); |
111 | } else { |
112 | // Start a new implicit round |
113 | $lbFactory->commitPrimaryChanges( $fnameTrxOwner ); |
114 | } |
115 | } |
116 | |
117 | public function onRunUpdateEnd( DeferrableUpdate $update ): void { |
118 | $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); |
119 | |
120 | $fnameTrxOwner = ( $update instanceof DeferrableCallback ) |
121 | ? $update->getOrigin() |
122 | : get_class( $update ) . '::doUpdate'; |
123 | |
124 | // Commit any pending changes from the explicit or implicit transaction round |
125 | $lbFactory->commitPrimaryChanges( $fnameTrxOwner ); |
126 | } |
127 | |
128 | public function onRunUpdateFailed( DeferrableUpdate $update ): void { |
129 | $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); |
130 | $lbFactory->rollbackPrimaryChanges( __METHOD__ ); |
131 | } |
132 | } |
133 | |
134 | /** @deprecated class alias since 1.42 */ |
135 | class_alias( DeferredUpdatesScopeMediaWikiStack::class, 'DeferredUpdatesScopeMediaWikiStack' ); |