MediaWiki  master
PoolCounter.php
Go to the documentation of this file.
1 <?php
24 use Wikimedia\ObjectFactory;
25 
47 abstract class PoolCounter {
48  /* Return codes */
49  public const LOCKED = 1; /* Lock acquired */
50  public const RELEASED = 2; /* Lock released */
51  public const DONE = 3; /* Another worker did the work for you */
52 
53  public const ERROR = -1; /* Indeterminate error */
54  public const NOT_LOCKED = -2; /* Called release() with no lock held */
55  public const QUEUE_FULL = -3; /* There are already maxqueue workers on this lock */
56  public const TIMEOUT = -4; /* Timeout exceeded */
57  public const LOCK_HELD = -5; /* Cannot acquire another lock while you have one lock held */
58 
60  protected $key;
62  protected $workers;
69  protected $slots = 0;
71  protected $maxqueue;
73  protected $timeout;
74 
78  private $isMightWaitKey;
82  private static $acquiredMightWaitKey = 0;
83 
87  private $fastStale;
88 
94  protected function __construct( array $conf, string $type, string $key ) {
95  $this->workers = $conf['workers'];
96  $this->maxqueue = $conf['maxqueue'];
97  $this->timeout = $conf['timeout'];
98  if ( isset( $conf['slots'] ) ) {
99  $this->slots = $conf['slots'];
100  }
101  $this->fastStale = $conf['fastStale'] ?? false;
102 
103  if ( $this->slots ) {
104  $key = $this->hashKeyIntoSlots( $type, $key, $this->slots );
105  }
106 
107  $this->key = $key;
108  $this->isMightWaitKey = !preg_match( '/^nowait:/', $this->key );
109  }
110 
119  public static function factory( string $type, string $key ) {
120  global $wgPoolCounterConf;
121  if ( !isset( $wgPoolCounterConf[$type] ) ) {
122  return new PoolCounterNull;
123  }
124  $conf = $wgPoolCounterConf[$type];
125 
127  $poolCounter = ObjectFactory::getObjectFromSpec(
128  $conf,
129  [
130  'extraArgs' => [ $conf, $type, $key ],
131  'assertClass' => self::class
132  ]
133  );
134 
135  return $poolCounter;
136  }
137 
141  public function getKey() {
142  return $this->key;
143  }
144 
152  abstract public function acquireForMe( $timeout = null );
153 
162  abstract public function acquireForAnyone( $timeout = null );
163 
171  abstract public function release();
172 
178  final protected function precheckAcquire() {
179  if ( $this->isMightWaitKey ) {
180  if ( self::$acquiredMightWaitKey ) {
181  /*
182  * The poolcounter itself is quite happy to allow you to wait
183  * on another lock while you have a lock you waited on already
184  * but we think that it is unlikely to be a good idea. So we
185  * made it an error. If you are _really_ _really_ sure it is a
186  * good idea then feel free to implement an unsafe flag or
187  * something.
188  */
189  return Status::newFatal( 'poolcounter-usage-error',
190  'You may only aquire a single non-nowait lock.' );
191  }
192  } elseif ( $this->timeout !== 0 ) {
193  return Status::newFatal( 'poolcounter-usage-error',
194  'Locks starting in nowait: must have 0 timeout.' );
195  }
196  return Status::newGood();
197  }
198 
203  final protected function onAcquire() {
204  self::$acquiredMightWaitKey |= $this->isMightWaitKey;
205  }
206 
211  final protected function onRelease() {
212  self::$acquiredMightWaitKey &= !$this->isMightWaitKey;
213  }
214 
227  protected function hashKeyIntoSlots( $type, $key, $slots ) {
228  return $type . ':' . ( hexdec( substr( sha1( $key ), 0, 4 ) ) % $slots );
229  }
230 
237  public function isFastStaleEnabled() {
238  return $this->fastStale;
239  }
240 }
StatusValue\newFatal
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:70
PoolCounter\onAcquire
onAcquire()
Update any lock tracking information when the lock is acquired.
Definition: PoolCounter.php:203
PoolCounter\LOCK_HELD
const LOCK_HELD
Definition: PoolCounter.php:57
PoolCounter\NOT_LOCKED
const NOT_LOCKED
Definition: PoolCounter.php:54
PoolCounterNull
A default PoolCounter, which provides no locking.
Definition: PoolCounterNull.php:27
PoolCounter\LOCKED
const LOCKED
Definition: PoolCounter.php:49
PoolCounter\release
release()
I have successfully finished my task.
PoolCounter\$workers
int $workers
Maximum number of workers working on tasks with the same key simultaneously.
Definition: PoolCounter.php:62
PoolCounter\onRelease
onRelease()
Update any lock tracking information when the lock is released.
Definition: PoolCounter.php:211
PoolCounter\$acquiredMightWaitKey
static bool $acquiredMightWaitKey
Whether this process holds a "might wait" lock key.
Definition: PoolCounter.php:82
PoolCounter\acquireForMe
acquireForMe( $timeout=null)
I want to do this task and I need to do it myself.
PoolCounter
When you have many workers (threads/servers) giving service, and a cached item expensive to produce e...
Definition: PoolCounter.php:47
PoolCounter\$isMightWaitKey
bool $isMightWaitKey
Whether the key is a "might wait" key.
Definition: PoolCounter.php:78
PoolCounter\$maxqueue
int $maxqueue
If this number of workers are already working/waiting, fail instead of wait.
Definition: PoolCounter.php:71
PoolCounter\$key
string $key
All workers with the same key share the lock.
Definition: PoolCounter.php:60
PoolCounter\factory
static factory(string $type, string $key)
Create a Pool counter.
Definition: PoolCounter.php:119
PoolCounter\acquireForAnyone
acquireForAnyone( $timeout=null)
I want to do this task, but if anyone else does it instead, it's also fine for me.
PoolCounter\isFastStaleEnabled
isFastStaleEnabled()
Is fast stale mode (T250248) enabled? This may be overridden by the PoolCounterWork subclass.
Definition: PoolCounter.php:237
PoolCounter\QUEUE_FULL
const QUEUE_FULL
Definition: PoolCounter.php:55
PoolCounter\$fastStale
bool $fastStale
Enable fast stale mode (T250248).
Definition: PoolCounter.php:87
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
PoolCounter\__construct
__construct(array $conf, string $type, string $key)
Definition: PoolCounter.php:94
PoolCounter\ERROR
const ERROR
Definition: PoolCounter.php:53
PoolCounter\$slots
int $slots
Maximum number of workers working on this task type, regardless of key.
Definition: PoolCounter.php:69
PoolCounter\getKey
getKey()
Definition: PoolCounter.php:141
$wgPoolCounterConf
$wgPoolCounterConf
Configuration for processing pool control, for use in high-traffic wikis.
Definition: DefaultSettings.php:2694
PoolCounter\hashKeyIntoSlots
hashKeyIntoSlots( $type, $key, $slots)
Given a key (any string) and the number of lots, returns a slot key (a prefix with a suffix integer f...
Definition: PoolCounter.php:227
PoolCounter\RELEASED
const RELEASED
Definition: PoolCounter.php:50
PoolCounter\TIMEOUT
const TIMEOUT
Definition: PoolCounter.php:56
PoolCounter\precheckAcquire
precheckAcquire()
Checks that the lock request is sane.
Definition: PoolCounter.php:178
PoolCounter\DONE
const DONE
Definition: PoolCounter.php:51
PoolCounter\$timeout
int $timeout
Maximum time in seconds to wait for the lock.
Definition: PoolCounter.php:73
$type
$type
Definition: testCompression.php:52