MediaWiki master
PoolCounterWork.php
Go to the documentation of this file.
1<?php
8
9use LogicException;
12
16abstract class PoolCounterWork {
18 protected $type = 'generic';
20 protected $cacheable = false; // does this override getCachedWork() ?
22 private $poolCounter;
23
29 public function __construct( string $type, string $key, ?PoolCounter $poolCounter = null ) {
30 $this->type = $type;
31 // MW >= 1.35
32 $this->poolCounter = $poolCounter ??
33 MediaWikiServices::getInstance()->getPoolCounterFactory()->create( $type, $key );
34 }
35
41 abstract public function doWork();
42
48 public function getCachedWork() {
49 return false;
50 }
51
59 public function fallback( $fast ) {
60 return false;
61 }
62
69 public function error( $status ) {
70 return false;
71 }
72
78 protected function isFastStaleEnabled() {
79 return $this->poolCounter->isFastStaleEnabled();
80 }
81
88 public function logError( $status ) {
89 $key = $this->poolCounter->getKey();
90
91 $this->poolCounter->getLogger()->info(
92 "Pool key '$key' ({$this->type}): " .
93 $status->getMessage()->inLanguage( 'en' )->useDatabase( false )->text()
94 );
95 }
96
124 public function execute( $skipcache = false ) {
125 if ( !$this->cacheable || $skipcache ) {
126 $status = $this->poolCounter->acquireForMe();
127 $skipcache = true;
128 } else {
129 if ( $this->isFastStaleEnabled() ) {
130 // In fast stale mode, check for existing locks by acquiring lock with 0 timeout
131 $status = $this->poolCounter->acquireForAnyone( 0 );
132 if ( $status->isOK() && $status->value === PoolCounter::TIMEOUT ) {
133 // Lock acquisition would block: try fallback
134 $staleResult = $this->fallback( true );
135 if ( $staleResult !== false ) {
136 return $staleResult;
137 }
138 // No fallback available, so wait for the lock
139 $status = $this->poolCounter->acquireForAnyone();
140 } // else behave as if $status were returned in slow mode
141 } else {
142 $status = $this->poolCounter->acquireForAnyone();
143 }
144 }
145
146 if ( !$status->isOK() ) {
147 // Respond gracefully to complete server breakage: just log it and do the work
148 $this->logError( $status );
149 return $this->doWork();
150 }
151
152 switch ( $status->value ) {
154 // Better to ignore nesting pool counter limits than to fail.
155 // Assume that the outer pool limiting is reasonable enough.
156 /* no break */
158 try {
159 return $this->doWork();
160 } finally {
161 $this->poolCounter->release();
162 }
163 // no fall-through, because try returns or throws
165 $result = $this->getCachedWork();
166 if ( $result === false ) {
167 if ( $skipcache ) {
168 // We shouldn't get here, because we called acquireForMe().
169 // which should not return DONE. If we do get here, this
170 // indicates a faulty test mock. Report the issue instead
171 // of calling $this->execute( true ) in endless recursion.
172 throw new LogicException(
173 'Got PoolCounter::DONE from acquireForMe() and ' .
174 'getCachedWork() returned nothing'
175 );
176 }
177
178 /* That someone else work didn't serve us.
179 * Acquire the lock for me
180 */
181 return $this->execute( true );
182 }
183 return $result;
184
187 $result = $this->fallback( false );
188
189 if ( $result !== false ) {
190 return $result;
191 }
192 /* no break */
193
194 /* These two cases should never be hit... */
196 default:
197 $errors = [
198 PoolCounter::QUEUE_FULL => 'pool-queuefull',
199 PoolCounter::TIMEOUT => 'pool-timeout',
200 ];
201
202 $status = Status::newFatal( $errors[$status->value] ?? 'pool-errorunknown' );
203 $this->logError( $status );
204 return $this->error( $status );
205 }
206 }
207}
208
210class_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:44