MediaWiki 1.44.0
PoolCounterWork.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\PoolCounter;
22
23use LogicException;
26
30abstract class PoolCounterWork {
32 protected $type = 'generic';
34 protected $cacheable = false; // does this override getCachedWork() ?
36 private $poolCounter;
37
43 public function __construct( string $type, string $key, ?PoolCounter $poolCounter = null ) {
44 $this->type = $type;
45 // MW >= 1.35
46 $this->poolCounter = $poolCounter ??
47 MediaWikiServices::getInstance()->getPoolCounterFactory()->create( $type, $key );
48 }
49
55 abstract public function doWork();
56
62 public function getCachedWork() {
63 return false;
64 }
65
73 public function fallback( $fast ) {
74 return false;
75 }
76
83 public function error( $status ) {
84 return false;
85 }
86
92 protected function isFastStaleEnabled() {
93 return $this->poolCounter->isFastStaleEnabled();
94 }
95
102 public function logError( $status ) {
103 $key = $this->poolCounter->getKey();
104
105 $this->poolCounter->getLogger()->info(
106 "Pool key '$key' ({$this->type}): " .
107 $status->getMessage()->inLanguage( 'en' )->useDatabase( false )->text()
108 );
109 }
110
138 public function execute( $skipcache = false ) {
139 if ( !$this->cacheable || $skipcache ) {
140 $status = $this->poolCounter->acquireForMe();
141 $skipcache = true;
142 } else {
143 if ( $this->isFastStaleEnabled() ) {
144 // In fast stale mode, check for existing locks by acquiring lock with 0 timeout
145 $status = $this->poolCounter->acquireForAnyone( 0 );
146 if ( $status->isOK() && $status->value === PoolCounter::TIMEOUT ) {
147 // Lock acquisition would block: try fallback
148 $staleResult = $this->fallback( true );
149 if ( $staleResult !== false ) {
150 return $staleResult;
151 }
152 // No fallback available, so wait for the lock
153 $status = $this->poolCounter->acquireForAnyone();
154 } // else behave as if $status were returned in slow mode
155 } else {
156 $status = $this->poolCounter->acquireForAnyone();
157 }
158 }
159
160 if ( !$status->isOK() ) {
161 // Respond gracefully to complete server breakage: just log it and do the work
162 $this->logError( $status );
163 return $this->doWork();
164 }
165
166 switch ( $status->value ) {
168 // Better to ignore nesting pool counter limits than to fail.
169 // Assume that the outer pool limiting is reasonable enough.
170 /* no break */
172 try {
173 return $this->doWork();
174 } finally {
175 $this->poolCounter->release();
176 }
177 // no fall-through, because try returns or throws
179 $result = $this->getCachedWork();
180 if ( $result === false ) {
181 if ( $skipcache ) {
182 // We shouldn't get here, because we called acquireForMe().
183 // which should not return DONE. If we do get here, this
184 // indicates a faulty test mock. Report the issue instead
185 // of calling $this->execute( true ) in endless recursion.
186 throw new LogicException(
187 'Got PoolCounter::DONE from acquireForMe() and ' .
188 'getCachedWork() returned nothing'
189 );
190 }
191
192 /* That someone else work didn't serve us.
193 * Acquire the lock for me
194 */
195 return $this->execute( true );
196 }
197 return $result;
198
201 $result = $this->fallback( false );
202
203 if ( $result !== false ) {
204 return $result;
205 }
206 /* no break */
207
208 /* These two cases should never be hit... */
210 default:
211 $errors = [
212 PoolCounter::QUEUE_FULL => 'pool-queuefull',
213 PoolCounter::TIMEOUT => 'pool-timeout',
214 ];
215
216 $status = Status::newFatal( $errors[$status->value] ?? 'pool-errorunknown' );
217 $this->logError( $status );
218 return $this->error( $status );
219 }
220 }
221}
222
224class_alias( PoolCounterWork::class, 'PoolCounterWork' );
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Class for dealing with PoolCounters using class members.
doWork()
Actually perform the work, caching it if needed.
error( $status)
Do something with the error, like showing it to the user.
execute( $skipcache=false)
Get the result of the work (whatever it is), or the result of the error() function.
fallback( $fast)
A work not so good (eg.
isFastStaleEnabled()
Should fast stale mode be used?
getCachedWork()
Retrieve the work from cache.
__construct(string $type, string $key, ?PoolCounter $poolCounter=null)
Semaphore semantics to restrict how many workers may concurrently perform a task.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54